-
Notifications
You must be signed in to change notification settings - Fork 0
/
day24.nim
134 lines (107 loc) · 2.84 KB
/
day24.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
121
122
123
124
125
126
127
128
129
130
131
132
133
134
import sequtils
import sets
import sugar
# Types
type
Direction = (float, float)
StringParser = object
stream: string
pointer: int
FloorPlan = HashSet[Direction]
# Constant directions
const
East = (1.0, 0.0)
West = (-1.0, 0.0)
NorthEast = (0.5, 1.0)
SouthEast = (0.5, -1.0)
NorthWest = (-0.5, 1.0)
SouthWest = (-0.5, -1.0)
AllDirections = [
East,
West,
NorthEast,
SouthEast,
NorthWest,
SouthWest
]
proc `+`(a, b: Direction): Direction =
(a[0] + b[0], a[1] + b[1])
# String parser
proc finished(parser: StringParser): bool =
parser.pointer >= parser.stream.len
proc next(parser: var StringParser): char =
if not parser.finished:
let nextChar = parser.stream[parser.pointer]
inc parser.pointer
return nextChar
'\0'
proc parser(stream: string): StringParser =
StringParser(
stream: stream,
pointer: 0
)
proc parseNextDirection(parser: var StringParser): Direction =
case parser.next:
of 'e':
East
of 'w':
West
of 'n':
if parser.next == 'e':
NorthEast
else:
NorthWest
of 's':
if parser.next == 'e':
SouthEast
else:
SouthWest
else:
East
proc parseLine(line: string): seq[Direction] =
var directions: seq[Direction]
var parser = line.parser
while not parser.finished:
directions.add(parser.parseNextDirection)
directions
# Parse input file
let inputFile = "resources/day24_input.txt"
var blackTiles: FloorPlan
for line in lines inputFile:
let tile = toHashSet([line.parseLine().foldl(a + b)])
blackTiles = blackTiles -+- tile
# Print results
echo "--- Part 1 Report ---"
echo "Black tiles = " & $blackTiles.card
## Part 2
# Utils
proc getSurrounding(tile: Direction): FloorPlan =
collect(initHashSet):
for direction in AllDirections:
{tile + direction}
proc filterWhite(floor: FloorPlan, tiles: FloorPlan): FloorPlan =
tiles - floor
proc filterBlack(floor: FloorPlan, tiles: FloorPlan): FloorPlan =
tiles * floor
proc applyRules(floor: FloorPlan): FloorPlan =
var nextState: FloorPlan
# Calculate tiles not flipped to white
for blackTile in floor:
let surroundingBlackTiles = floor.filterBlack(blackTile.getSurrounding())
if surroundingBlackTiles.card > 0 and surroundingBlackTiles.card <= 2:
nextState.incl(blackTile)
# Calculate white tiles flipped to black
var updatedTiles: FloorPlan
for blackTile in floor:
updatedTiles.incl(blackTile.getSurrounding())
let whiteTiles = floor.filterWhite(updatedTiles)
for whiteTile in whiteTiles:
let surroundingBlackTiles = floor.filterBlack(whiteTile.getSurrounding())
if surroundingBlackTiles.card == 2:
nextState.incl(whiteTile)
nextState
for day in 1..100:
blackTiles = blackTiles.applyRules
# Print results
echo "--- Part 2 Report ---"
echo "Black tiles = " & $blackTiles.card