Dia 13: Robot repartidor de regalos

Los elfos del Polo Norte han creado un robot 馃 especial que ayuda a Pap谩 Noel a distribuir regalos dentro de un gran almac茅n. El robot se mueve en un plano 2D y partimos desde el origen (0, 0).

Queremos saber si, tras ejecutar una serie de movimientos, el robot vuelve a estar justo donde empez贸.

Las 贸rdenes b谩sicas del robot son:

L: Mover hacia la izquierda
R: Mover hacia la derecha
U: Mover hacia arriba
D: Mover hacia abajo

Pero tambi茅n tiene ciertos modificadores para los movimientos:

*: El movimiento se realiza con el doble de intensidad (ej: *R significa RR)
!: El siguiente movimiento se invierte (ej: R!L se considera como RR)
?: El siguiente movimiento se hace s贸lo si no se ha hecho antes (ej: R?R significa R)

Nota: Cuando el movimiento se invierte con ! se contabiliza el movimiento invertido y no el original. Por ejemplo, !U?U invierte el movimiento de U, por lo que contabiliza que se hizo el movimiento D pero no el U. As铆 !U?U se traduce como D?U y, por lo tanto, se har铆a el movimiento U final.

Debes devolver:

true: si el robot vuelve a estar justo donde empez贸
[x, y]: si el robot no vuelve a estar justo donde empez贸, devolver la posici贸n donde se detuvo
isRobotBack('R')     // [1, 0]
isRobotBack('RL')    // true
isRobotBack('RLUD')  // true
isRobotBack('*RU')   // [2, 1]
isRobotBack('R*U')   // [1, 2]
isRobotBack('LLL!R') // [-4, 0]
isRobotBack('R?R')   // [1, 0]
isRobotBack('U?D')   // true
isRobotBack('R!L')   // [2,0]
isRobotBack('U!D')   // [0,2]
isRobotBack('R?L')   // true
isRobotBack('U?U')   // [0,1]
isRobotBack('*U?U')  // [0,2]
isRobotBack('U?D?U') // true

// Ejemplos paso a paso:
isRobotBack('R!U?U') // [1,0]
// 'R'  -> se mueve a la derecha 
// '!U' -> se invierte y se convierte en 'D'
// '?U' -> se mueve arriba, porque no se ha hecho el movimiento 'U'

isRobotBack('UU!U?D') // [0,1]
// 'U'  -> se mueve arriba
// 'U'  -> se mueve arriba
// '!U' -> se invierte y se convierte en 'D'
// '?D' -> no se mueve, ya que ya se hizo el movimiento 'D'

Solution

function isRobotBack(moves) {
  let position = [0, 0]
  let visited = new Set()
  let skipNext = false
  let invertNext = false

  const directionMap = {
    L: [-1, 0],
    R: [1, 0],
    U: [0, 1],
    D: [0, -1]
  }

  for (let i = 0; i < moves.length; i++) {
    const command = moves[i]

    if (skipNext) {
      skipNext = false
      continue
    }

    if (command === '*') {
      if (i + 1 < moves.length && directionMap[moves[i + 1]]) {
        const move = directionMap[moves[i + 1]]
        const effectiveMove = invertNext ? [-move[0], -move[1]] : move
        position[0] += 2 * effectiveMove[0]
        position[1] += 2 * effectiveMove[1]
        visited.add(`${effectiveMove[0]},${effectiveMove[1]}`)
        skipNext = true
        invertNext = false
      }
    } else if (command === '!') {
      invertNext = true
    } else if (command === '?') {
      if (i + 1 < moves.length && directionMap[moves[i + 1]]) {
        const move = moves[i + 1]
        const moveVector = directionMap[move]

        const effectiveMove = invertNext
          ? [-moveVector[0], -moveVector[1]]
          : moveVector

        const effectiveKey = `${effectiveMove[0]},${effectiveMove[1]}`

        if (!visited.has(effectiveKey)) {
          visited.add(effectiveKey)
          position[0] += effectiveMove[0]
          position[1] += effectiveMove[1]
        }
        invertNext = false
        skipNext = true
      }
    } else if (directionMap[command]) {
      let move = directionMap[command]
      if (invertNext) {
        move = [-move[0], -move[1]]
        invertNext = false
      }

      position[0] += move[0]
      position[1] += move[1]

      const moveKey = `${move[0]},${move[1]}`
      visited.add(moveKey)
    }
  }

  return position[0] === 0 && position[1] === 0 ? true : position
}

// Test cases
console.log(isRobotBack('R')) // [1, 0]
console.log(isRobotBack('RL')) // true
console.log(isRobotBack('RLUD')) // true
console.log(isRobotBack('*RU')) // [2, 1]
console.log(isRobotBack('R*U')) // [1, 2]
console.log(isRobotBack('LLL!R')) // [-4, 0]
console.log(isRobotBack('R?R')) // [1, 0]
console.log(isRobotBack('U?D')) // true
console.log(isRobotBack('R!L')) // [2, 0]
console.log(isRobotBack('U!D')) // [0, 2]
console.log(isRobotBack('R?L')) // true
console.log(isRobotBack('U?U')) // [0, 1]
console.log(isRobotBack('*U?U')) // [0, 2]
console.log(isRobotBack('U?D?U')) // true
console.log(isRobotBack('R!U?U')) // [1, 0]
console.log(isRobotBack('UU!U?D')) // [0, 1]