const Position = require('./position.js')
const { BLANK_SPACE, COORDS, INSTRUCTIONS } = require('../utils')
// Used to set the new robot's orientation
const right = {
[COORDS.N]: COORDS.E,
[COORDS.E]: COORDS.S,
[COORDS.S]: COORDS.W,
[COORDS.W]: COORDS.N
}
const left = {
[COORDS.N]: COORDS.W,
[COORDS.W]: COORDS.S,
[COORDS.S]: COORDS.E,
[COORDS.E]: COORDS.N
}
const isLeftTurn = (instruction) => {
return instruction === INSTRUCTIONS.LEFT
}
const isRightTurn = (instruction) => {
return instruction === INSTRUCTIONS.RIGHT
}
const isForwardMovement = (instruction) => {
return instruction === INSTRUCTIONS.FORWARD
}
/**
* Creates a new Robot 🤖 which is able to follow instructions from Earth 🌍
*/
class Robot {
/**
* The robot uses the {@link Grid} and a default {@link Position}
* @param grid {Grid}
*/
constructor (grid) {
this.grid = grid
this.position = new Position()
}
/**
* Gets the robot position
* @returns {Position}
*/
getPosition () {
return this.position
}
/**
* Given a Position (x, y, orientation), sets the robot position and orientation
* @param startPosition {String}
*/
setPosition (startPosition) {
const [x, y, orientation] = startPosition.split(BLANK_SPACE)
this.position.x = x
this.position.y = y
this.position.orientation = orientation
}
/**
* Perform all the movements. In the moment robot is lost, does nothing
*
* @param {String} instructions
* @returns {string} All the instructions
*/
move (instructions) {
for (let i = 0; i < instructions.length; i++) {
if (this.position.lost) {
break
}
// Get current instruction
const instruction = instructions.charAt(i)
if (isLeftTurn(instruction)) {
this.turnLeft()
}
if (isRightTurn(instruction)) {
this.turnRight()
}
if (isForwardMovement(instruction)) {
this.moveForwards()
}
}
return this.position.toString()
}
/**
* Move one step forward, according to the orientation and change the position:
* - Orientation (N) means `y + 1`
* - Orientation (S) means `y - 1`
* - Orientation (E) means `x + 1`
* - Orientation (W) means `x - 1`
*/
moveForwards () {
const startingPosition = this.position.toString()
// Do nothing if the robot is lost or it's a forbidden position
if (this.position.lost || this.grid.hasForbidden(startingPosition)) {
return
}
if (this.position.orientation === COORDS.N) {
this.position.y++
}
if (this.position.orientation === COORDS.E) {
this.position.x++
}
if (this.position.orientation === COORDS.S) {
this.position.y--
}
if (this.position.orientation === COORDS.W) {
this.position.x--
}
// After the robot has moved, check if it's off the grid
if (this.position.isOffTheGrid(this.grid)) {
this.grid.addForbiddenPosition(startingPosition)
}
}
/**
* Changes the orientation of the robot 90º left, according to the current orientation
* @example
* Robot is facing North (N)
* Turn Left
* Now, robot is facing West (W)
*/
turnLeft () {
this.position.orientation = left[this.position.orientation]
}
/**
* Changes the orientation of the robot 90º right, according to the current orientation
* @example
* Robot is facing South (S)
* Turn Right
* Now, robot is facing West (W)
*/
turnRight () {
this.position.orientation = right[this.position.orientation]
}
/**
* Check if robot is lost
* @returns {boolean}
*/
isLost () {
return this.position.lost
}
}
module.exports = Robot