-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsolution.nim
133 lines (112 loc) · 2.93 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
121
122
123
124
125
126
127
128
129
130
131
132
133
import ../../lib/imports
iterator hexDirs(s: string): string =
var i = 0
while i < s.len:
if s[i] == 'n':
if i + 1 < s.len and s[i + 1] == 'e':
yield "ne"
i += 2
elif i + 1 < s.len and s[i + 1] == 'w':
yield "nw"
i += 2
elif s[i] == 's':
if i + 1 < s.len and s[i + 1] == 'e':
yield "se"
i += 2
elif i + 1 < s.len and s[i + 1] == 'w':
yield "sw"
i += 2
else:
yield $s[i]
i += 1
when defined(test):
block:
doAssert "esenee".hexDirs.toSeq == @["e", "se", "ne", "e"]
type
Pos = (int, int, int)
proc `+`(a, b: Pos): Pos =
(a[0] + b[0], a[1] + b[1], a[2] + b[2])
const dPos = [
(1, 0, -1),
(0, 1, -1),
(-1, 1, 0),
(-1, 0, 1),
(0, -1, 1),
(1, -1, 0),
]
const dirs = ["e", "se", "sw", "w", "nw", "ne"]
proc move(a: Pos, d: string): Pos =
a + dPos[dirs.find(d)]
proc parse(input: string): HashSet[Pos] =
for line in input.split("\n"):
var p = (0, 0, 0)
for dir in line.hexDirs:
p = p.move(dir)
if p notin result:
result.incl p
else:
result.excl p
proc part1(input: string): int =
let tiles = input.parse
tiles.len
when defined(test):
let input = """
sesenwnenenewseeswwswswwnenewsewsw
neeenesenwnwwswnenewnwwsewnenwseswesw
seswneswswsenwwnwse
nwnwneseeswswnenewneswwnewseswneseene
swweswneswnenwsewnwneneseenw
eesenwseswswnenwswnwnwsewwnwsene
sewnenenenesenwsewnenwwwse
wenwwweseeeweswwwnwwe
wsweesenenewnwwnwsenewsenwwsesesenwne
neeswseenwwswnwswswnw
nenwswwsewswnenenewsenwsenwnesesenew
enewnwewneswsewnwswenweswnenwsenwsw
sweneswneswneneenwnewenewwneswswnese
swwesenesewenwneswnwwneseswwne
enesenwswwswneneswsenwnewswseenwsese
wnwnesenesenenwwnenwsewesewsesesew
nenewswnwewswnenesenwnesewesw
eneswnwswnwsenenwnwnwwseeswneewsenese
neswnwewnwnwseenwseesewsenwsweewe
wseweeenwnesenwwwswnew
""".strip
block:
doAssert part1(input) == 10
proc step(tiles: HashSet[Pos]): HashSet[Pos] =
for p in tiles:
var blacks = 0
for d in dirs:
if p.move(d) in tiles: blacks += 1
if not (blacks == 0 or blacks > 2): result.incl p
var cands = initHashSet[Pos]()
for p in tiles:
for d in dirs:
cands.incl p.move(d)
for p in cands:
var blacks = 0
for d in dirs:
if p.move(d) in tiles: blacks += 1
if blacks == 2: result.incl p
when defined(test):
block:
var tiles = input.parse
var expected = @[15, 12, 25, 14, 23, 28, 41, 37, 49, 37]
for i in 1 .. 10:
tiles = tiles.step
doAssert tiles.len == expected[i - 1]
expected = @[132, 259, 406, 566, 788, 1106, 1373, 1844, 2208]
for i in 11 .. 100:
tiles = tiles.step
if i mod 10 == 0:
doAssert tiles.len == expected[i div 10 - 2]
proc part2(input: string): int =
var tiles = input.parse
for _ in 1 .. 100:
tiles = tiles.step
tiles.len
when isMainModule and not defined(test):
let input = readFile("input").strip
echo part1(input)
echo part2(input)