AdventJS 2023: Reto del Día 5
Tags: spanish, javascript, webdev, challenge
Published: 2023-12-06 05:14:11

Solución al [reto #5](https://adventjs.dev/es/challenges/2023/5) del [AdventJS 2023](https://adventjs.dev/es)
[Solución del reto anterior](https://dev.to/fenriuz/adventjs-2023-reto-del-dia-4-2h4g)
[Solución del siguiente reto](https://dev.to/fenriuz/adventjs-2023-reto-del-dia-6-1lpk)

{%- # TOC start (generated with https://github.com/derlin/bitdowntoc) -%}

- [Descripción del Reto](#descripción-del-reto)
- [Análisis](#análisis)
   * [Entradas](#entradas)
   * [Salida](#salida)
   * [Consideraciones](#consideraciones)
- [Solución](#solución)
   * [Código](#código)
   * [Soluciones de la comunidad](#soluciones-de-la-comunidad)

{%- # TOC end -%}

## Descripción del Reto
Santa 🎅 está probando su nuevo trineo eléctrico, el CyberReindeer, en una carretera del Polo Norte. La carretera se representa con una cadena de caracteres, donde:

`.` = Carretera
`S` = Trineo de Santa
`*` = Barrera abierta
`|` = Barrera cerrada
Ejemplo de carretera: `S...|....|.....`

Cada unidad de tiempo, el trineo avanza una posición a la derecha. Si encuentra una barrera cerrada, se detiene hasta que la barrera se abra. Si está abierta, la atraviesa directamente.

Todas las barreras empiezan cerradas, pero después de 5 unidades de tiempo, se abren todas para siempre.

Crea una función que simule el movimiento del trineo durante un tiempo dado y devuelva un array de cadenas representando el estado de la carretera en cada unidad de tiempo:

```javascript
const road = 'S..|...|..'
const time = 10 // unidades de tiempo
const result = cyberReindeer(road, time)

/* -> result:
[
  'S..|...|..', // estado inicial
  '.S.|...|..', // avanza el trineo la carretera
  '..S|...|..', // avanza el trineo la carretera
  '..S|...|..', // el trineo para en la barrera
  '..S|...|..', // el trineo para en la barrera
  '...S...*..', // se abre la barrera, el trineo avanza
  '...*S..*..', // avanza el trineo la carretera
  '...*.S.*..', // avanza el trineo la carretera
  '...*..S*..', // avanza el trineo la carretera
  '...*...S..', // avanza por la barrera abierta
]
*/
```
El resultado es un array donde cada elemento muestra la carretera en cada unidad de tiempo.

Ten en cuenta que si el trineo está en la misma posición que una barrera, entonces toma su lugar en el array.

## Análisis
Para resolver este reto debemos ir moviendo la letra `S` dentro del string y detenerlo al encontrar una barrera (`|`), la barrera se abrirá (`*`) al pasar 5 unidades de tiempo. Debemos ir guardando en un arreglo el recorrido de la letra `S` hasta que se acaben las unidades de tiempo.

### Entradas
1. Road(`road`): El string original por el cual el trineo hará su recorrido.
2. Time(`time`): Un número con las unidades de tiempo.

### Salida
* Un arreglo con el historial del recorrido que hizo el trineo

### Consideraciones
* Debemos detener el trineo al encontrar una barrera y guardarlo en el historial aunque no se mueva de allí
* Cuando el trineo pasa sobre una barrera abierta (`*`) éste la va a reemplazar en el string y una vez la haya pasado se debe volver a colocar la barrera abierta (`*`)

## Solución
La posición inicial del trineo se identifica al principio. La función itera por cada unidad de tiempo, avanzando el trineo si no hay una barrera cerrada delante. En la quinta unidad de tiempo, todas las barreras se abren permanentemente. El estado de la carretera se actualiza y guarda en un array en cada iteración, reflejando la posición del trineo y el estado de las barreras. El resultado final es un array que muestra el estado de la carretera en cada momento del tiempo dado.

### Código
```javascript
/**
 * Simula el movimiento del trineo de Santa en una carretera durante un tiempo dado.
 * 
 * @param {string} road - Representación de la carretera con '.', 'S', '|', y '*'.
 * @param {number} time - Número de unidades de tiempo para simular.
 * @return {string[]} - Array que representa el estado de la carretera en cada unidad de tiempo.
 */
function cyberReindeer(road, time) {
  // Almacena el estado de la carretera en cada unidad de tiempo
  const roadStates = [road];
  
  // Encuentra la posición inicial del trineo
  let sledPosition = road.indexOf("S");
  
  // Carácter que será reemplazado por el trineo cuando se mueve
  let replacedChar = ".";

  // Itera por cada unidad de tiempo, menos uno, ya que el estado inicial ya está incluido
  for (let i = 0; i < time - 1; i++) {
    // Obtiene el estado actual de la carretera
    let currentRoadState = roadStates[i];

    // En la quinta iteración (unidad de tiempo 5), todas las barreras se abren
    if (i === 4) {
      currentRoadState = currentRoadState.replace(/[|]/g, "*");
    }

    // Verifica si la siguiente posición del trineo no es una barrera cerrada
    if (currentRoadState[sledPosition + 1] !== "|") {
      // Prepara la nueva posición del trineo
      // concatenandólo al elemento que anteriormente estaba en esa posición
      const newSledPosition = `${replacedChar}S`;
      
      // Actualiza el carácter reemplazado por el trineo antes de ser reemplazado
      replacedChar = currentRoadState[sledPosition + 1];

      // Construye el nuevo estado de la carretera con el trineo movido una posición
      const firstPart = currentRoadState.substring(0, sledPosition);
      const lastPart = currentRoadState.substring(sledPosition + 2);
      currentRoadState = firstPart + newSledPosition + lastPart;
      
      // Actualiza la posición del trineo
      sledPosition += 1;
    }

    // Añade el estado actualizado de la carretera al array
    roadStates.push(currentRoadState);
  }

  // Retorna el array con el estado de la carretera en cada unidad de tiempo
  return roadStates;
}
```

### Soluciones de la comunidad

Solución por [SantiMenendez19](https://github.com/SantiMenendez19/adventjs/blob/main/2023/challenge05/solution.js):

```javascript
function cyberReindeer(road, time) {
    let result = []
    let timePassed = 0
    let pos = 0
    let aux = "."
    while (time > 0) {
        result.push(road)
        time--
        timePassed++
        if (timePassed >= 5) road = road.replace(/\|/gi, "*")
        if (road[pos+1] === '.' || road[pos+1] === '*') {
            road = road.split("")
            road[pos] = aux
            aux = road[pos+1]
            road[pos+1] = "S"
            road = road.join("")
            pos++
        }
    }
    return result
}
```

Solución por [Achalogy](https://github.com/Achalogy/advent-js-2023/blob/main/retos/reto-5/main.ts):

```javascript
function cyberReindeer(road, time) {
  let moves = [road]
  let a = 0
  let b = "."

  for (let i = 1; i < time; i++) {
    if (i == 5) road = road.replace(/\|/g, "*")
    const newRoad = road.replace(/S[\.\*]/, `${b}S`)
    if (newRoad != road) {
      a++
      b = road[a]
    }
    road = newRoad
    moves.push(road)
  }

  return moves;
}
```

Y ese fue el reto para el 5 de diciembre y sus soluciones. ¿Tienes otra solución alternativa? ¡Déjala en los comentarios!