-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathy24day15.kt
More file actions
123 lines (119 loc) · 4.61 KB
/
Copy pathy24day15.kt
File metadata and controls
123 lines (119 loc) · 4.61 KB
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
import kotlin.math.abs
import kotlin.time.measureTimedValue
fun main() {
data class Pos(val i: Int, val j: Int)
fun Pos.move(dir: Char) = when (dir) {
'^' -> Pos(i - 1, j)
'v' -> Pos(i + 1, j)
'<' -> Pos(i, j - 1)
'>' -> Pos(i, j + 1)
else -> error("Impossible")
}
infix fun Pos.distance(that: Pos) = abs(i - that.i) + abs(j - that.j)
operator fun Array<CharArray>.get(pos: Pos) = this[pos.i][pos.j]
operator fun Array<CharArray>.set(pos: Pos, value: Char) { this[pos.i][pos.j] = value }
val map = generateSequence { readln().ifEmpty { null } }.toList()
val moves = generateSequence { readlnOrNull() }.joinToString("")
measureTimedValue { // part 1
val a = Array(map.size) { i -> CharArray(map[i].length) { j -> map[i][j] } }
val startPos = a.indices.firstNotNullOf { i ->
a[i].indices.firstNotNullOfOrNull { j ->
Pos(i, j).takeIf { a[it] == '@' }
}
}
var pos = startPos
for (dir in moves) {
fun nextFreePos() = generateSequence(pos) { it.move(dir) }.drop(1)
.takeWhile { a[it] != '#' }.filter { a[it] == '.' }.firstOrNull()
val freePos = nextFreePos() ?: continue
a[pos] = '.'
when (pos distance freePos) {
1 -> pos = freePos
else -> {
pos = pos.move(dir)
a[freePos] = 'O'
}
}
a[pos] = '@'
}
a.asSequence().flatMapIndexed { i, row ->
row.mapIndexed { j, char ->
(i to j).takeIf { char == 'O' }
}
}.filterNotNull().sumOf { (i, j) -> 100 * i + j }
}.also(::println)
measureTimedValue { // part 2
val a = Array(map.size) { i ->
CharArray(map[i].length shl 1) { j ->
when (val c = map[i][j shr 1]) {
'O' -> if (j and 1 == 0) '[' else ']'
'@' -> if (j and 1 == 0) '@' else '.'
else -> c
}
}
}
val startPos = a.indices.firstNotNullOf { i ->
a[i].indices.firstNotNullOfOrNull { j ->
Pos(i, j).takeIf { a[it] == '@' }
}
}
var pos = startPos
for (dir in moves) {
if (dir in "<>") {
fun nextFreePos() = generateSequence(pos) { it.move(dir) }.drop(1)
.takeWhile { a[it] != '#' }.filter { a[it] == '.' }.firstOrNull()
val freePos = nextFreePos() ?: continue
a[pos] = '.'
when (val dist = pos distance freePos) {
1 -> pos = freePos
else -> {
pos = pos.move(dir)
generateSequence(pos) { it.move(dir) }.take(dist).forEachIndexed { j, p ->
a[p] = if ((j and 1 == 0) xor (dir == '>')) '[' else ']'
}
}
}
a[pos] = '@'
} else {
fun moveRow(boxes: Iterable<Pos>): Boolean {
val nextSlots = boxes.mapTo(mutableSetOf()) { it.move(dir) }
if (nextSlots.any { a[it] == '#' }) return false
nextSlots.apply {
removeIf { a[it] == '.' }
buildList<Pos> {
this@apply.forEach { slot ->
when {
a[slot] == '[' -> add(slot.move('>'))
a[slot] == ']' -> add(slot.move('<'))
}
}
}.also { addAll(it) }
}
return (nextSlots.isEmpty() || moveRow(nextSlots)).also { moving ->
if (moving) {
boxes.forEach {
a[it.move(dir)] = a[it]
a[it] = '.'
}
}
}
}
if (moveRow(listOf(pos))) {
a[pos] = '.'
pos = pos.move(dir)
a[pos] = '@'
}
}
/*
a.forEach {
println(it.joinToString(""))
}
*/
}
a.asSequence().flatMapIndexed { i, row ->
row.mapIndexed { j, char ->
(i to j).takeIf { char == '[' }
}
}.filterNotNull().sumOf { (i, j) -> 100 * i + j }
}.also(::println)
}