Skip to content

Commit 3b80e42

Browse files
authored
Merge pull request #29 from palinkiewicz/2023_d22
2023 Day 22
2 parents 0b72cf4 + cc9c800 commit 3b80e42

File tree

3 files changed

+1348
-0
lines changed

3 files changed

+1348
-0
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,4 @@ I started taking part in the event in 2023 but may also consider doing tasks fro
2828
| [Day 19: Aplenty](https://adventofcode.com/2023/day/19) | [Solution](/adventofcode2023/Day19.kt) | [Inputs](/resources/adventofcode2023/Day19.txt) |
2929
| [Day 20: Pulse Propagation](https://adventofcode.com/2023/day/20) | [Solution](/adventofcode2023/Day20.kt) | [Inputs](/resources/adventofcode2023/Day20.txt) |
3030
| [Day 21: Step Counter](https://adventofcode.com/2023/day/21) | [Solution (Part 1 only)](/adventofcode2023/Day21.kt) | [Inputs](/resources/adventofcode2023/Day21.txt) |
31+
| [Day 22: Sand Slabs](https://adventofcode.com/2023/day/22) | [Solution](/adventofcode2023/Day22.kt) | [Inputs](/resources/adventofcode2023/Day22.txt) |

adventofcode2023/Day22.kt

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
package adventofcode2023
2+
3+
import java.io.File
4+
import java.util.PriorityQueue
5+
6+
object Day22 {
7+
private const val EMPTY = -1
8+
private const val FLOOR = 0
9+
10+
private val bricks = File("resources/adventofcode2023/Day22.txt")
11+
.readLines()
12+
.withIndex()
13+
.map { brick ->
14+
val startEnd = brick.value.split('~').map { positions ->
15+
Vector3(positions.split(',').map { it.toInt() })
16+
}
17+
18+
Brick(brick.index + 1, startEnd[0], startEnd[1])
19+
}
20+
21+
private val map: Array<Array<Array<Int>>> =
22+
Array(bricks.maxOf { it.end.x } + 1) {
23+
Array(bricks.maxOf { it.end.y } + 1) {
24+
Array(bricks.maxOf { it.end.z } + 1) {
25+
if (it == 0) FLOOR else EMPTY
26+
}
27+
}
28+
}
29+
30+
private fun initializeBricksMap() =
31+
bricks.forEach { it.updateMap(true) }
32+
33+
private data class Vector3(val x: Int, val y: Int, val z: Int) {
34+
fun lower() = Vector3(x, y, z - 1)
35+
}
36+
37+
private fun Vector3(positions: List<Int>) = Vector3(positions[0], positions[1], positions[2])
38+
39+
private data class Brick(val id: Int, var start: Vector3, var end: Vector3) {
40+
private fun iterateThroughAllCubes(fixedZ: Int = 0, onEveryCube: (Int, Int, Int) -> Unit) {
41+
for (x in start.x..end.x)
42+
for (y in start.y..end.y)
43+
if (fixedZ > 0)
44+
onEveryCube(x, y, fixedZ)
45+
else for (z in start.z..end.z)
46+
onEveryCube(x, y, z)
47+
}
48+
49+
fun verticalNeighborsIds(higher: Boolean): Set<Int> {
50+
val supportingIds = mutableSetOf<Int>()
51+
52+
iterateThroughAllCubes(if (higher) end.z + 1 else start.z - 1) { x, y, z ->
53+
val currentId = map[x][y][z]
54+
if (currentId > EMPTY && !supportingIds.contains(currentId)) supportingIds.add(currentId)
55+
}
56+
57+
return supportingIds
58+
}
59+
60+
private fun lower() {
61+
start = start.lower()
62+
end = end.lower()
63+
}
64+
65+
fun updateMap(fill: Boolean) {
66+
iterateThroughAllCubes { x, y, z ->
67+
map[x][y][z] = if (fill) id else -1
68+
}
69+
}
70+
71+
fun numberOfSupporting(): Int =
72+
verticalNeighborsIds(false).size
73+
74+
fun supportedBricks(): List<Brick> =
75+
verticalNeighborsIds(true).map { bricks[it - 1] }
76+
77+
fun fall(): Boolean {
78+
return if (numberOfSupporting() == 0) {
79+
updateMap(false)
80+
lower()
81+
updateMap(true)
82+
true
83+
} else {
84+
false
85+
}
86+
}
87+
}
88+
89+
private fun makeBricksFall() {
90+
var anyFell = true
91+
92+
while (anyFell) {
93+
anyFell = false
94+
95+
bricks.forEach {
96+
if (it.fall()) anyFell = true
97+
}
98+
}
99+
}
100+
101+
private fun numberOfSafeToDisintegrate(): Int =
102+
bricks.count { brick ->
103+
brick.supportedBricks().all { it.numberOfSupporting() > 1 }
104+
}
105+
106+
private fun numberOfBrickThatWouldFall(brick: Brick): Int {
107+
val currentBricks = PriorityQueue<Brick> { brick1, brick2 -> brick1.end.z - brick2.end.z }
108+
val fallenIds = mutableListOf(brick.id)
109+
var fallenCount = 0
110+
111+
currentBricks.addAll(brick.supportedBricks())
112+
113+
while (currentBricks.isNotEmpty()) {
114+
val current = currentBricks.remove()
115+
116+
if (current.verticalNeighborsIds(false).all { fallenIds.contains(it) }) {
117+
if (!fallenIds.contains(current.id)) fallenIds.add(current.id)
118+
currentBricks.addAll(current.supportedBricks().filterNot { currentBricks.contains(it) })
119+
fallenCount++
120+
}
121+
}
122+
123+
println("${brick.id}: $fallenCount")
124+
return fallenCount
125+
}
126+
127+
fun initialize() {
128+
initializeBricksMap()
129+
makeBricksFall()
130+
}
131+
132+
fun part1() = println(numberOfSafeToDisintegrate())
133+
134+
fun part2() = println(bricks.sumOf { numberOfBrickThatWouldFall(it) })
135+
}
136+
137+
fun main() {
138+
Day22.initialize()
139+
Day22.part1()
140+
Day22.part2()
141+
}

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy