-
Notifications
You must be signed in to change notification settings - Fork 7
/
22.kt
197 lines (181 loc) · 7.72 KB
/
22.kt
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
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
// This solution was not golfed whatsoever, it still prints both parts,
// but is certainly not general to solve any input. However, some of the complexity arises
// a basic because of an ASCII visualization which has been added.
//
// Set this to true in order to paint a colorful ASCII image (needs ANSI support)
val visualize = false
// This solution only works for inputs of shape:
//
// ## # ## #
// # or ## or # or ##
// ## # ## #
// # ## # ##
//
// Important is:
// * it has to be higher than its width
// * the middle column must be filled
// * the remaining 2 blocks have to be on opposite sites, one offset to the other by y=2 blocks
val dirs = listOf(0 to 1, 1 to 0, 0 to -1, -1 to 0)
class Painter(field: List<String>) {
val visField = field.map { it.toMutableList() }
var time = 0
val coords: MutableList<Pair<Int, Int>> = mutableListOf()
val atTime: MutableMap<Pair<Int, Int>, Int> = mutableMapOf()
val MAX_TRAIL_LENGTH = 500
fun add(y: Int, x: Int, c: Char) {
visField[y][x] = c
atTime[y to x] = time
coords.add(y to x)
if (coords.size > MAX_TRAIL_LENGTH)
coords.removeAt(0)
}
fun paint(withBackground: Boolean = false) {
if (!visualize)
return
print("[H")
var c =
if (withBackground)
visField[0].indices.flatMap { visField.indices.map { y -> y to it } }
else
coords
for ((y, x) in c) {
if (!withBackground && (y to x) !in atTime)
continue
fun t(mult: Double = 1.0, atLeast: Int = 50, max: Int = 255): Int =
maxOf(atLeast, (max - (time - atTime[y to x]!!) * mult).toInt())
when (visField[y][x]) {
'#' -> "[38;2;105;15;0m"
'.' -> "[38;2;120;120;130m"
' ' -> "[38;2;10;20;10m"
else -> "[38;2;${t(1.0)};${t(0.25)};${t(0.01)}m"
}.run(::print)
print("[${x};${y}H▓")
}
println()
time++
}
}
fun solve(asCube: Boolean, field: List<String>, seq: List<String>) {
val painter = Painter(field)
val instructions = Regex("(\\d+|[RL])").findAll(seq[0]).toList()
var currDir = 0
var (cy, cx) = 0 to field[0].indexOfFirst { it == '.' }
painter.paint(true)
for (instruction in instructions.map { it.value }) {
if (instruction in "RL") {
currDir = (currDir + if (instruction == "R") 1 else -1).mod(4)
continue
}
var (ny, nx) = cy to cx
for (i in 1..instruction.toInt()) {
painter.paint()
var ny3 = ny + dirs[currDir].first
var nx3 = nx + dirs[currDir].second
var dir3 = currDir
val yIsShorter = field.size < field[0].length
val alongShortAxis = (dirs[currDir].first != 0 && yIsShorter) || (dirs[currDir].second != 0 && !yIsShorter)
if (asCube && (ny3 !in field.indices || nx3 !in field[0].indices)) {
if (!yIsShorter && alongShortAxis) {
dir3 = (dir3 + 2).mod(4)
ny3 = (50*2 + ny3 - ny3 % 50 + (49 - ny3 % 50)).mod(field.size)
nx3 = nx3 + dirs[dir3].second
assert(ny3 in field.indices && nx3 in field[0].indices) { "$ny3 $nx3 out of bounds" }
}
}
ny3 = ny3.mod(field.size)
nx3 = nx3.mod(field[0].length)
ny = (ny + dirs[currDir].first).mod(field.size)
nx = (nx + dirs[currDir].second).mod(field[cy].length)
var ny2 = ny
var nx2 = nx
if (field[ny][nx] == ' ' && field[ny2][nx2] == ' ') {
var nyxp: MutableList<Pair<Int, Int>> = mutableListOf()
var nyx2p: MutableList<Pair<Int, Int>> = mutableListOf()
var nyx3p: MutableList<Pair<Int, Int>> = mutableListOf()
painter.add(ny3, nx3, '?')
val moveStraight = !asCube || alongShortAxis && (cy in 0..49 || cy in 100..149)
while (field[ny][nx] == ' ' && field[ny2][nx2] == ' ') {
// If there is an adjacent block go diagonally
if (!moveStraight) {
ny = (ny + dirs[(currDir+1).mod(4)].first).mod(field.size)
nx = (nx + dirs[(currDir+1).mod(4)].second).mod(field[cy].length)
ny2 = (ny2 + dirs[(currDir-1).mod(4)].first).mod(field.size)
nx2 = (nx2 + dirs[(currDir-1).mod(4)].second).mod(field[cy].length)
}
if (field[ny][nx] != ' ' || field[ny2][nx2] != ' ' || field[ny3][nx3] != ' ')
break
if (moveStraight) {
ny3 = ny3 + dirs[dir3].first
nx3 = nx3 + dirs[dir3].second
}
else {
ny = (ny + dirs[currDir].first).mod(field.size)
nx = (nx + dirs[currDir].second).mod(field[cy].length)
ny2 = (ny2 + dirs[currDir].first).mod(field.size)
nx2 = (nx2 + dirs[currDir].second).mod(field[cy].length)
}
if (asCube && (ny3 !in field.indices || nx3 !in field[0].indices)) {
if (!yIsShorter && alongShortAxis) {
dir3 = (dir3 + 2).mod(4)
ny3 = (100 + ny3 - ny3 % 50 + (49 - ny3 % 50)).mod(field.size)
nx3 = nx3 + dirs[dir3].second
assert(ny3 in field.indices && nx3 in field[0].indices) { "$ny3 $nx3 out of bounds" }
}
}
ny3 = ny3.mod(field.size)
nx3 = nx3.mod(field[0].length)
nyxp.add(ny to nx)
nyx2p.add(ny2 to nx2)
nyx3p.add(ny3 to nx3)
}
if (field[ny][nx] != ' ') {
if (field[ny][nx] != '#')
currDir = (currDir+1).mod(4)
}
else if (field[ny2][nx2] != ' ') {
ny = ny2
nx = nx2
nyxp = nyx2p
if (field[ny][nx] != '#')
currDir = (currDir-1).mod(4)
}
else if (field[ny3][nx3] != ' ') {
ny = ny3
nx = nx3
nyxp = nyx3p
if (asCube && field[ny][nx] != '#')
currDir = (currDir+2).mod(4)
}
for ((nyp, nxp) in nyxp) {
painter.add(nyp, nxp, if (currDir % 2 == 0) '\\' else '/')
painter.paint()
}
}
if (field[ny][nx] == '.') {
cy = ny
cx = nx
painter.add(cy, cx, ">v<^"[currDir])
}
else if (field[ny][nx] == '#')
break
}
}
painter.paint()
println(1000 * (cy+1) + 4 * (cx+1) + currDir)
}
fun main() {
var (field, seq) = generateSequence(::readlnOrNull).joinToString("\n").split("\n\n").map { it.split("\n") }
// Part 1
solve(asCube=false, field, seq)
// Part 2
val cube = field.map { it.toMutableList() }
// Rotate last face of cube in input to make it easier
for (y in 0..49) {
for (x in 0..49) {
cube[199-x][50+y] = cube[150+y][x]
cube[150+y][x] = ' '
}
}
field = cube.map { it.joinToString("") }
solve(asCube=true, field, seq)
}