Los problemas en la tienda de alquiler de trineos ya están resueltos, así que es hora de ponerse en marcha hacia nuestras merecidas vacaciones. La cuestión es que, como hemos alquilado un trineo low cost con muy poco angulo de giro (por no decir ninguno), y el camino está lleno de árboles, vamos a tener que estudiar el mapa para ver que ángulos de salida utilizar de manera que nos choquemos con el menor número de árboles posibles en nuestro camino.

video creado por ManicD7

Parte 1

La entrada de nuestro puzzle va a ser un mapa que nos indica las posiciones de los árboles.

..##.......
#...#...#..
.#....#..#.
..#.#...#.#

Las posiciones con . indican un área libre, mientras las # marcan los árboles. Empezando desde la esquina superior izquierda, posición (0,0) debemos llegar a la última fila avanzando 3 posiciones horizontales y una en vertical en cada paso. La tarea es contar con cuantos árboles nos chocaríamos al hacer esto, teniendo en cuenta que si nos salimos del mapa por la derecha, este se repite de manera infinita.

A priori parece un ejercicio sencillo para el que manejo dos opciones:

  • Trasformar el mapa a un array de puntos (x,y) en el que unicamente se guarden las posiciones de los árboles
  • Utilizar directamente las cadenas de entrada que definen el mapa para comprobar la existencia de árboles.

La primera opción es más barata en consumo de memoria ya que no almacenamos toda la definición del mapa. Aún así, creo que el tiempo necesario para buscar los puntos a posteriori va a ser superior al necesario para comprobar la existencia de determinados caracteres en las cadenas, así que opto por la segunda idea:

class SlopeCalculator {
  private rows = 0;
  private cols = 0;
  constructor(private map: string[]) {
    //Guardar dimensiones del mapa
    this.rows = map.length;
    this.cols = map[0].length;
  }

  public treesInSlope = (right: number, down: number): number => {
    let x = 0,
      y = 0,
      treesCount = 0;
    // Hasta que lleguemos abajo
    while (y < this.rows) {
      if (this.map[y][x] == "#") treesCount++;
      x += right;
      y += down;
      if (x > this.cols - 1) x -= this.cols; // Si salimos del mapa por la derecha, lo repetimos
    }
    return treesCount;
  };
}

La clase SlopeCalculator almacena tres propiedades privadas: el array de strings que conforman el mapa y las dimensiones de ancho y alto del mismo. En la función, y conociendo a Eric y su gusto por la reutilización, decido informar como parámetros los pasos horizontales y verticales que debemos dar en cada ciclo.

La función es bastante directa: comenzando desde (0,0) – aunque en mi juego de datos no hay árbol en esta posición, por lo que podríamos haber empezado desde (3,1) – avanzamos por el mapa. Si en la posición x de la cadena correspondiente a la fila y hay una árbol (this.map[y][x]), sumamos uno a nuestro contador.

Y si nos salimos por la derecha, es decir, si la posición x es mayor al numero de columnas, la ajustamos para volver a colocarla en el array restando el numero de columnas, con lo que efectivamente logramos la repetición infinita del mapa hacia la derecha.

Una vez que estamos en la última fila hemos terminado y solo queda devolver la cuenta de los árboles encontrados.

NOTA MENTAL PARA FUTURO: Los arrays comienzan en 0. El tamaño es igual a la longitud menos 1. Llevas 30 años programando, ¿no es hora de que lo sepas?… 20 minutos he estado repasando el código porque funcionaba con el mapa de muestra pero no daba la respuesta correcta con el juego de datos.

Parte 2

Como era de esperar por el enunciado del primer problema, Eric nos propone que calculemos el mismo dato con diferentes ángulos de ataque. Debemos devolver el resultado de la multiplicación del número de árboles encontrados al procesar el mapa con 5 avances diferentes. Como la función ya esta preparada para recibir el desplazamiento horizontal y vertical como parámetros, solo debemos utilizarla:

console.log(
  "Answer:",
  slopeCalculator.treesInSlope(1, 1) *
    slopeCalculator.treesInSlope(3, 1) *
    slopeCalculator.treesInSlope(5, 1) *
    slopeCalculator.treesInSlope(7, 1) *
    slopeCalculator.treesInSlope(1, 2)
);

Y así termina el día 3, que, si exceptuamos mi empanada mental mañanera, ha sido sorprendentemente sencillo. Pero no os confieis, ¡en breve la dificultad de los problemas va a aumentar!

Puedes descargar el código completo de este ejemplo desde GitHub: oddbytes.net/adventofcode
Solución al problema en Excel del usuario minichado
Free WordPress Themes, Free Android Games