-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsolution.nim
120 lines (101 loc) · 2.68 KB
/
solution.nim
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
import ../../lib/imports
const FLOOR = '.'
const EMPTY = 'L'
const OCCUPIED = '#'
type
Grid = seq[string]
proc countOccupiedAdj(grid: var Grid, r, c: int): int =
let (rows, cols) = (grid.len, grid[0].len)
for dr in -1 .. 1:
for dc in -1 .. 1:
if (dr, dc) == (0, 0): continue
let (nr, nc) = (r + dr, c + dc)
if nr notin 0 ..< rows: continue
if nc notin 0 ..< cols: continue
if grid[nr][nc] == OCCUPIED: result += 1
proc step(grid: var Grid): (bool, Grid) =
let (rows, cols) = (grid.len, grid[0].len)
var next = grid
var changed = false
for r in 0 ..< rows:
for c in 0 ..< cols:
case grid[r][c]
of EMPTY:
if grid.countOccupiedAdj(r, c) == 0:
next[r][c] = OCCUPIED
changed = true
of OCCUPIED:
if grid.countOccupiedAdj(r, c) >= 4:
next[r][c] = EMPTY
changed = true
else: discard
(changed, next)
proc countOccupied(grid: sink Grid): int =
grid.mapIt(it.count(OCCUPIED)).sum
proc parse(input: string): Grid =
input.split("\n")
proc part1(input: string): int =
var grid = input.parse
while true:
let (changed, next) = grid.step
if not changed: break
grid = next
grid.countOccupied
when defined(test):
let input = """
L.LL.LL.LL
LLLLLLL.LL
L.L.L..L..
LLLL.LL.LL
L.LL.LL.LL
L.LLLLL.LL
..L.L.....
LLLLLLLLLL
L.LLLLLL.L
L.LLLLL.LL
""".strip
block:
doAssert part1(input) == 37
proc countOccupiedAdj2(grid: var Grid, r, c: int): int =
let (rows, cols) = (grid.len, grid[0].len)
template inRange(r, c: int): bool =
r in 0 ..< rows and c in 0 ..< cols
for dr in -1 .. 1:
for dc in -1 .. 1:
if (dr, dc) == (0, 0): continue
var (nr, nc) = (r + dr, c + dc)
while inRange(nr, nc) and grid[nr][nc] == FLOOR:
(nr, nc) = (nr + dr, nc + dc)
if inRange(nr, nc) and grid[nr][nc] == OCCUPIED:
result += 1
proc step2(grid: var Grid): (bool, Grid) =
let (rows, cols) = (grid.len, grid[0].len)
var next = grid
var changed = false
for r in 0 ..< rows:
for c in 0 ..< cols:
case grid[r][c]
of EMPTY:
if grid.countOccupiedAdj2(r, c) == 0:
next[r][c] = OCCUPIED
changed = true
of OCCUPIED:
if grid.countOccupiedAdj2(r, c) >= 5:
next[r][c] = EMPTY
changed = true
else: discard
(changed, next)
proc part2(input: string): int =
var grid = input.parse
while true:
let (changed, next) = grid.step2
if not changed: break
grid = next
grid.countOccupied
when defined(test):
block:
doAssert part2(input) == 26
when isMainModule and not defined(test):
let input = readFile("input").strip
echo part1(input)
echo part2(input)