Advertisement
Guest User

Untitled

a guest
Dec 14th, 2023
150
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. import { readFileSync } from 'fs'
  2.  
  3. enum Tile {
  4.     Round = 'O',
  5.     Cube = '#',
  6.     Empty = '.',
  7. }
  8.  
  9. type Grid = Tile[][]
  10.  
  11. function parse(input: string): Grid {
  12.     return input
  13.         .trim()
  14.         .split('\n')
  15.         .map((line) => line.split('').map((char) => char as Tile))
  16. }
  17.  
  18. function render(grid: Grid) {
  19.     for (let y = 0; y < grid.length; y++) {
  20.         let row = ''
  21.         for (let x = 0; x < grid[0].length; x++) {
  22.             row += String(grid[y][x])
  23.         }
  24.         console.log(row)
  25.     }
  26.     console.log('----------------------------------------')
  27. }
  28.  
  29. function fullyTilt(
  30.     grid: Grid,
  31.     direction: 'north' | 'south' | 'east' | 'west',
  32. ): Grid {
  33.     switch (direction) {
  34.         case 'north':
  35.             return applyUntilZero(grid, tiltNorth)
  36.         case 'south':
  37.             return applyUntilZero(grid, tiltSouth)
  38.         case 'west':
  39.             return applyUntilZero(grid, tiltWest)
  40.         case 'east':
  41.             return applyUntilZero(grid, tiltEast)
  42.     }
  43. }
  44.  
  45. // Returns the number of round rocks that moved north one cell after one round of simulation.
  46. function tiltNorth(grid: Grid): number {
  47.     let count = 0
  48.     for (let y = 1; y < grid.length; y++) {
  49.         for (let x = 0; x < grid[0].length; x++) {
  50.             if (grid[y][x] === Tile.Round && grid[y - 1][x] === Tile.Empty) {
  51.                 grid[y - 1][x] = Tile.Round
  52.                 grid[y][x] = Tile.Empty
  53.                 count++
  54.             }
  55.         }
  56.     }
  57.     return count
  58. }
  59.  
  60. function tiltSouth(grid: Grid): number {
  61.     let count = 0
  62.     for (let y = grid.length - 2; y >= 0; y--) {
  63.         for (let x = 0; x < grid[0].length; x++) {
  64.             if (grid[y][x] === Tile.Round && grid[y + 1][x] === Tile.Empty) {
  65.                 grid[y + 1][x] = Tile.Round
  66.                 grid[y][x] = Tile.Empty
  67.                 count++
  68.             }
  69.         }
  70.     }
  71.     return count
  72. }
  73.  
  74. function tiltWest(grid: Grid): number {
  75.     let count = 0
  76.     for (let x = 1; x < grid[0].length; x++) {
  77.         for (let y = 0; y < grid.length; y++) {
  78.             if (grid[y][x] === Tile.Round && grid[y][x - 1] === Tile.Empty) {
  79.                 grid[y][x - 1] = Tile.Round
  80.                 grid[y][x] = Tile.Empty
  81.                 count++
  82.             }
  83.         }
  84.     }
  85.     return count
  86. }
  87.  
  88. function tiltEast(grid: Grid): number {
  89.     let count = 0
  90.     for (let x = grid[0].length - 2; x >= 0; x--) {
  91.         for (let y = 0; y < grid.length; y++) {
  92.             if (grid[y][x] === Tile.Round && grid[y][x + 1] === Tile.Empty) {
  93.                 grid[y][x + 1] = Tile.Round
  94.                 grid[y][x] = Tile.Empty
  95.                 count++
  96.             }
  97.         }
  98.     }
  99.     return count
  100. }
  101.  
  102. function applyUntilZero(input: Grid, fn: (grid: Grid) => number): Grid {
  103.     let result = 0
  104.     while ((result = fn(input)) !== 0) {}
  105.     return input
  106. }
  107.  
  108. function calcWeight(grid: Grid): number {
  109.     let total = 0
  110.     for (let y = 0; y < grid.length; y++) {
  111.         let weight = grid.length - y
  112.         for (let x = 0; x < grid[0].length; x++) {
  113.             if (grid[y][x] === Tile.Round) {
  114.                 total += weight
  115.             }
  116.         }
  117.     }
  118.     return total
  119. }
  120.  
  121. function part1(input: string): number {
  122.     const grid = parse(input)
  123.     render(grid)
  124.     let moved = 0
  125.     while ((moved = tiltNorth(grid)) > 0) {}
  126.     return calcWeight(grid)
  127. }
  128.  
  129. function part2(input: string): number {
  130.     const grid = parse(input)
  131.     const seen = new Map<string, number>() // grid -> loop first seen
  132.     let cycling = false
  133.     const end = 1_000_000_000
  134.     for (let i = 0; i < end; i++) {
  135.         fullyTilt(grid, 'north')
  136.         fullyTilt(grid, 'west')
  137.         fullyTilt(grid, 'south')
  138.         fullyTilt(grid, 'east')
  139.         const key = String(grid)
  140.         if (!cycling && seen.has(key)) {
  141.             const cycleStart = seen.get(key)!
  142.             const period = i - cycleStart
  143.             i = end - ((end - cycleStart) % period)
  144.             cycling = true
  145.         }
  146.         seen.set(key, i)
  147.     }
  148.     return calcWeight(grid)
  149. }
  150.  
  151. let input = `O....#....
  152. O.OO#....#
  153. .....##...
  154. OO.#O....O
  155. .O.....O#.
  156. O.#..O.#.#
  157. ..O..#O..O
  158. .......O..
  159. #....###..
  160. #OO..#....`
  161.  
  162. input = readFileSync('day14.txt', { encoding: 'utf8' })
  163.  
  164. console.log('part 1:', part1(input))
  165. console.log('part 2:', part2(input))
  166.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement