Day 24
This commit is contained in:
		
							parent
							
								
									b107ee7053
								
							
						
					
					
						commit
						b4aaa46c5c
					
				
							
								
								
									
										22
									
								
								24/input
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								24/input
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,22 @@
 | 
				
			|||||||
 | 
					#.######################################################################################################################################################
 | 
				
			||||||
 | 
					#>.^v.>^v>><>>^>>v>v^>.<>^.>v^v>..<<><>>>v.><^<.>^.<^>^v^>>v<^>><.^<^.<v>v><><^^<^>>^<<<>.>.>^^^<^<^>.>^v.>.>^>^v<<^^<>><vv<><>>>v^.>^<vvv>.^>v.>.v<v.<#
 | 
				
			||||||
 | 
					#<^^^><<vv<vv^^><>><>vv.vv<>vvvv<vv.>^>^>v^vvv>.<^>v<>>.<><<><>v<v^^<^.v^^><<><^><<.v.vv<<><.<<<<v^^>><^<><^<<<<.>v<^v<v>^>>>><.v>^>.>^<^>>v<v<^vv<v>v<#
 | 
				
			||||||
 | 
					#>>>>^.>.^v>v<.^<^vv^^^<>.>>.>><<.v<v^><^><.<<<><.^v^^v<><v^v><vv<<v<..<<^<.<>^<^v.^>^<v^v.^<v>v<><>>>^v<v.^^<><>><>v<^v>>>^v<v^>v<^vvv><v>^><<><^v>>^>#
 | 
				
			||||||
 | 
					#><<>^>v>.<^^v><v.<>v^<<<>^^v>^.v<<>><>v.v>v^.v>>>^<^><.>>v<<<>vv^.>^>^<><^.>.v^^<v<.^>^><>^<v>vv^v>v^<>><<vv>>>v^^<^v>>>v.<<>.v<><^^v<.^>v>.<^^><vv.^>#
 | 
				
			||||||
 | 
					#<.v^vv^vv>><v>^>>^.vvv^^<v<.v^>><<>v<v<<^<<<vv.>><>v.^>vvv<v<v>^<>>v><.>^.>.^<<<.^vvv>^..^>>.v<v.^v^<^^<<^<^>^v>^v<vvv.v^^v<<<>^v<<<v><>v^<<^><.v>v<v>#
 | 
				
			||||||
 | 
					#<^v^><>v^<.>vv>.^<<<vv^^<><^<^.^^<.^vv^>v^^.^<^>^.^<><><^<<>><vv<v^<>v<><>v^^v<.<v^<v>vvv>^>>^<^><>>^vv<^>><v><^.<<v><v.>^v^v>>>^<vv>v<^<><>.^^>.v><<>#
 | 
				
			||||||
 | 
					#<.><^v>^<.>>v<v>v<^v^v.^>v<.v>.<vv>^>v<v<<>^^.<>.<.vvv<^>v^.^<^v>^.>.v<.v>><<<^vv^.^<<^<^v<v^^^>.><>v.^^.^><<.<vvvv<v><<^vv.<^^^^>^<.<><<>>^>v>.^^v.<<#
 | 
				
			||||||
 | 
					#<<^.>v<><>.^>>^v<<^>vv<^v>><.<v^v^<<><v><^^.^^^>^.><^>v^v<<<<>>^>v>^v<^<>..v<.<v<><>v^>v^^v..<>^<><>^v<<v<<><<.v>...>^^v>.>v^.^>vv>^v<>v><<^.>^^..<<^<#
 | 
				
			||||||
 | 
					#><v^<^..>>v<v.<>vvv>v<v^>>>.v^<^v<>.>^<.<<^<>.<..>.^.>^^>.^.^^>v.v^>v<^>^v.<v^>v^^^vv><^>^>>>v><v<>>>..v.<^<.<<<>>><^<<v>>^<.>^^^<><^<.<^>^<v.^>vv>vv>#
 | 
				
			||||||
 | 
					#<><>v^..>v>^^^^<.v>v>..<>><^><<^v.v.<v^<v><><<<v>>>^^>>v<<>^^<^^^>v.<<>v^<v><v^<<v>>^v>>v><v^^>vv^<^v<^v^.><>vv>>>.>>v^<v^v>><^^v.^<v.><v^^<<<v^>>^v^>#
 | 
				
			||||||
 | 
					#>v><>><<^.>v^.v<<<v><^vv<.v^>v<.>vv>v>>^<^<<><>v>v<v..v<^<.vvv<^>^^v<^.>.^^^>^^v.^.>^>>>^><v<.v<^^^^.v.vv<<vv<.>v<^>v^<<vv^v><v>v^>>v.^.^<<.vv>^^^<^v<#
 | 
				
			||||||
 | 
					#<v^<>>^>>^..vv<^<<<v.v.^vv<.<^^<v^<.>^<.^.<<v^^^<^><>.>>>><^<>^>^v>><v^>v.<.^<v>^^>><><.>^v^>^<>^<^^.<^>^^^^^^vv<>vv^v^v>^v^<v<vv><<vv<^^^.>>^><<<.^>>#
 | 
				
			||||||
 | 
					#<.<v^.>>><vv^.<^^^>>>.><v<v>^<>>.^^vv>>^<<<^v><^^<v<>>^^^^<v^<>^^>><^>v^<<>>v<^.>vvvv>>^<.^>.v<^^<<v>>.vv.v^v<>>>><^v^>>>.v.^^v<<v>v^^>^v>^v<><.v><^v.#
 | 
				
			||||||
 | 
					#><<^v><<<.v<^^><^v<^v.<<<.^^.v>vvvv>^>><^^v<>.<>><<.v^>..^<>.><^>^>^v^^>v<<vv>^>vvv.>^^>^^<<>v>v^>^^^<^v>.v>^<><^<.v<^><<>^.^>>><<v^>v^v^v<^v>>^^^><^<#
 | 
				
			||||||
 | 
					#<^>v<>.>>^.v>^<v><>.v.^^v>^<..v.^>^>.v>>><vv^<>^^>v><>vv.<v<v^vv<.^vv<><v>>>^v><v^vvvvv.<vv>>^v<<.v>v^>v><<<^.<<<<>vv>^>>^<>^^<vvv^<vvvvvv><^^<<<>^^<>#
 | 
				
			||||||
 | 
					#>>.>>.^>..<^<^.<<v<><>..^^<..v<.><^^<v.v^v><>^vv<v<^v<^>.v<vvvv><<<>^>^v^>v<>><vv^v<>>>>>v<v<>^.>><v<v.>><v<v^^<v.<><.<>^^^^v<<^>>.><<.><.v^^..>>>.v>>#
 | 
				
			||||||
 | 
					#>v<v^^<^vvv.>^<>>v^v.vv^>v^vvvvv<>.v^.v<.><>^>>^<<v<^^v>v><^.>>^><>v<vv>v<<^>^>^.<v>vv<<>^^>^<<>v><v>.<<^.<>><<^<<.^<^<<<.^>.<.vv>v^v<^>vvv>^v<<<<v<<<#
 | 
				
			||||||
 | 
					#<^<>v^.^<><>^<>^>v<v.^v..v..vv^.<.^^>^>^><.vv>>.<^..^^^<^<.^^<^^v^<^.<<<<<v<^<<><v>^v.<<>.^>><^>^v>><<v<>^v^<<^>>v<<^.v<<^vv>>v>^.v^^^<><vv^^<<>.v.<><#
 | 
				
			||||||
 | 
					#..vv<v><^vv>.v<v<^v><vvv>.v>^v^>>vv^.^>v.v^^<<>^^<>^<^^>.<^v<v>^>^<v<<v<>v<^^^>v>><><<><.<<><^<v<<>v^^>>v><>^v^.v>^^v<^><><^v<^<vv.vvv><><<>v<<><>v<.>#
 | 
				
			||||||
 | 
					#>>.<^^>><<<^>v<^^>>^<<>><<.<^^^<^^^<^<v<^<<^><<v<v<^^>vv<<^v>.^<^^>><>^^^.>v>v^<^>>v><<^<^^^>v><<>^^v><>v..<.^^>..vv.<v>>>^<<v^<v^^v>>>>.>vv.>>^v>^v<.#
 | 
				
			||||||
 | 
					######################################################################################################################################################.#
 | 
				
			||||||
							
								
								
									
										162
									
								
								24/solution.mjs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										162
									
								
								24/solution.mjs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,162 @@
 | 
				
			|||||||
 | 
					import { readFileSync } from 'node:fs';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const input = readFileSync('input', 'utf-8');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Direction
 | 
				
			||||||
 | 
					const D = {
 | 
				
			||||||
 | 
					  R: 0,
 | 
				
			||||||
 | 
					  D: 1,
 | 
				
			||||||
 | 
					  L: 2,
 | 
				
			||||||
 | 
					  U: 3
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Blizzard {
 | 
				
			||||||
 | 
					  constructor(width, height, x, y, direction) {
 | 
				
			||||||
 | 
					    this.width = width;
 | 
				
			||||||
 | 
					    this.height = height;
 | 
				
			||||||
 | 
					    this.x = x;
 | 
				
			||||||
 | 
					    this.y = y;
 | 
				
			||||||
 | 
					    this.direction = direction;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  posAtTime(t) {
 | 
				
			||||||
 | 
					    switch (this.direction) {
 | 
				
			||||||
 | 
					      case D.R: return [(this.x + t) % this.width, this.y];
 | 
				
			||||||
 | 
					      case D.D: return [this.x, (this.y + t) % this.height];
 | 
				
			||||||
 | 
					      case D.L: return [
 | 
				
			||||||
 | 
					        this.width - 1 - (this.width - 1 - this.x + t) % this.width,
 | 
				
			||||||
 | 
					        this.y
 | 
				
			||||||
 | 
					      ];
 | 
				
			||||||
 | 
					      case D.U: return [
 | 
				
			||||||
 | 
					        this.x,
 | 
				
			||||||
 | 
					        this.height - 1 - (this.height - 1 - this.y + t) % this.height,
 | 
				
			||||||
 | 
					      ];
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const initialState = input
 | 
				
			||||||
 | 
					  .split('\n')
 | 
				
			||||||
 | 
					  .filter(line => !!line.trim() && !/#.*#.*#/.test(line))
 | 
				
			||||||
 | 
					  .map(line => line.replace(/^#(.*)#$/, '$1'));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const height = initialState.length;
 | 
				
			||||||
 | 
					const width = initialState[0].length;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const blizzards = initialState
 | 
				
			||||||
 | 
					  .flatMap((line, y) => line
 | 
				
			||||||
 | 
					    .split('')
 | 
				
			||||||
 | 
					    .flatMap((c, x) => {
 | 
				
			||||||
 | 
					      let direction;
 | 
				
			||||||
 | 
					      switch (c) {
 | 
				
			||||||
 | 
					        case '>': direction = D.R; break;
 | 
				
			||||||
 | 
					        case 'v': direction = D.D; break;
 | 
				
			||||||
 | 
					        case '<': direction = D.L; break;
 | 
				
			||||||
 | 
					        case '^': direction = D.U; break;
 | 
				
			||||||
 | 
					        case '.': return [];
 | 
				
			||||||
 | 
					        default: throw new Error(`Invalid character: ${c}`);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      return [new Blizzard(width, height, x, y, direction)];
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function lcm(a, b) {
 | 
				
			||||||
 | 
					  const larger = Math.max(a, b);
 | 
				
			||||||
 | 
					  const smaller = Math.min(a, b);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  for (let m = 1; ; m++) {
 | 
				
			||||||
 | 
					    const v = larger * m;
 | 
				
			||||||
 | 
					    if (v % smaller === 0) {
 | 
				
			||||||
 | 
					      return v;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Frame {
 | 
				
			||||||
 | 
					  constructor(blizzards, width, height, t) {
 | 
				
			||||||
 | 
					    this.width = width;
 | 
				
			||||||
 | 
					    this.height = height;
 | 
				
			||||||
 | 
					    this.t = t;
 | 
				
			||||||
 | 
					    this.data = new Array(height).fill().map(_ => '.'.repeat(width));
 | 
				
			||||||
 | 
					    for (const blizzard of blizzards) {
 | 
				
			||||||
 | 
					      const [x, y] = blizzard.posAtTime(t);
 | 
				
			||||||
 | 
					      this.data[y] = (
 | 
				
			||||||
 | 
					        this.data[y].slice(0, x) +
 | 
				
			||||||
 | 
					        '#' +
 | 
				
			||||||
 | 
					        this.data[y].slice(x + 1)
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  getPos(x, y) {
 | 
				
			||||||
 | 
					    // Start
 | 
				
			||||||
 | 
					    if (x === 0 && y === -1) {
 | 
				
			||||||
 | 
					      return '.';
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (x === width - 1 && y === this.height) {
 | 
				
			||||||
 | 
					      return '.';
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return this.data[y]?.[x] ?? '#';
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  movesFromPos(x, y) {
 | 
				
			||||||
 | 
					    return [
 | 
				
			||||||
 | 
					      [x, y],
 | 
				
			||||||
 | 
					      [x + 1, y],
 | 
				
			||||||
 | 
					      [x, y + 1],
 | 
				
			||||||
 | 
					      [x - 1, y],
 | 
				
			||||||
 | 
					      [x, y - 1]
 | 
				
			||||||
 | 
					    ].filter(pos =>
 | 
				
			||||||
 | 
					      this.getPos(...pos) !== '#'
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  print() {
 | 
				
			||||||
 | 
					    console.log(this.data.join('\n'));
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const nFrames = lcm(width, height);
 | 
				
			||||||
 | 
					const frames = new Array(nFrames)
 | 
				
			||||||
 | 
					  .fill()
 | 
				
			||||||
 | 
					  .map((_, t) => new Frame(blizzards, width, height, t));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function fastestRoute(start, end, timeOffset = 0) {
 | 
				
			||||||
 | 
					  let positions = [start];
 | 
				
			||||||
 | 
					  for (let t = timeOffset + 1; ; t++) {
 | 
				
			||||||
 | 
					    const frame = frames[t % nFrames];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const newPositions = [];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (const [x, y] of positions) {
 | 
				
			||||||
 | 
					      const moves = frame.movesFromPos(x, y);
 | 
				
			||||||
 | 
					      if (moves.find(move => move[0] === end[0] && move[1] === end[1])) {
 | 
				
			||||||
 | 
					        return t;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      newPositions.push(...frame.movesFromPos(x, y));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Remove duplicates and assign to positions
 | 
				
			||||||
 | 
					    positions = newPositions.filter((pos1, i, arr) =>
 | 
				
			||||||
 | 
					      arr.findLastIndex(
 | 
				
			||||||
 | 
					        pos2 => pos1[0] === pos2[0] && pos1[1] === pos2[1]
 | 
				
			||||||
 | 
					      ) === i
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const start = [0, -1];
 | 
				
			||||||
 | 
					const end = [width - 1, height];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const fastestTime = fastestRoute(start, end);
 | 
				
			||||||
 | 
					console.log('The fastest time to navigate the blizzards is:', fastestTime);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const fastestTimeWithSnacks = fastestRoute(
 | 
				
			||||||
 | 
					  start,
 | 
				
			||||||
 | 
					  end,
 | 
				
			||||||
 | 
					  fastestRoute(end, start, fastestTime)
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					console.log(
 | 
				
			||||||
 | 
					  'The fastest time with a return trip for snacks is:',
 | 
				
			||||||
 | 
					  fastestTimeWithSnacks
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
		Loading…
	
		Reference in New Issue
	
	Block a user