Skip to content

Commit e220947

Browse files
committed
Solution 2025-12 (Christmas Tree Farm)
1 parent f2a5ff8 commit e220947

File tree

2 files changed

+167
-0
lines changed

2 files changed

+167
-0
lines changed
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
package de.ronny_h.aoc.year2025.day12
2+
3+
import de.ronny_h.aoc.AdventOfCode
4+
import de.ronny_h.aoc.extensions.collections.split
5+
import de.ronny_h.aoc.extensions.grids.SimpleCharGrid
6+
7+
fun main() = ChristmasTreeFarm().run(454, 0)
8+
9+
class ChristmasTreeFarm : AdventOfCode<Int>(2025, 12) {
10+
override fun part1(input: List<String>): Int {
11+
val presents = input.parsePresents()
12+
return presents.regions.count { PresentsSpace(it, presents.shapes).allShapesFit() }
13+
}
14+
15+
override fun part2(input: List<String>): Int {
16+
return 0
17+
}
18+
}
19+
20+
fun List<String>.parsePresents(): Presents {
21+
val chunks = split()
22+
val shapes = chunks.dropLast(1).map { it.parseShape() }
23+
val regions = chunks.last().map { it.parseRegion() }
24+
return Presents(shapes, regions)
25+
}
26+
27+
private fun List<String>.parseShape() = PresentShape(
28+
index = first().dropLast(1).toInt(),
29+
input = drop(1),
30+
)
31+
32+
private fun String.parseRegion(): Region {
33+
val (dimensions, presents) = split(": ")
34+
val (width, length) = dimensions.split("x").map(String::toInt)
35+
return Region(width, length, presents.split(" ").map(String::toInt))
36+
}
37+
38+
data class Presents(val shapes: List<PresentShape>, val regions: List<Region>)
39+
40+
data class Region(val width: Int, val length: Int, val presents: List<Int>) {
41+
val area: Int
42+
get() = width * length
43+
}
44+
45+
class PresentShape(private val index: Int, input: List<String>) : SimpleCharGrid(input, nullElement = BACKGROUND) {
46+
47+
companion object {
48+
const val BACKGROUND = '.'
49+
}
50+
51+
val numberOfTiles
52+
get() = forEachElement { _, _, element ->
53+
if (element != BACKGROUND) 1 else 0
54+
}.sum()
55+
56+
override fun equals(other: Any?): Boolean {
57+
if (other !is PresentShape) return false
58+
return index == other.index && toString() == other.toString()
59+
}
60+
61+
override fun hashCode(): Int = index
62+
}
63+
64+
class PresentsSpace(private val region: Region, private val shapes: List<PresentShape>) {
65+
66+
fun allShapesFit(): Boolean {
67+
val presentsToAdd = region.presents.mapIndexed { i, times ->
68+
if (times == 0) null else shapes[i] to times
69+
}.filterNotNull()
70+
71+
return presentsToAdd.sumOf { (shape, times) -> times * shape.numberOfTiles } <= region.area
72+
}
73+
74+
}
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
package de.ronny_h.aoc.year2025.day12
2+
3+
import de.ronny_h.aoc.extensions.asList
4+
import io.kotest.core.spec.style.StringSpec
5+
import io.kotest.data.forAll
6+
import io.kotest.data.row
7+
import io.kotest.matchers.shouldBe
8+
9+
class ChristmasTreeFarmTest : StringSpec({
10+
11+
val input = """
12+
0:
13+
###
14+
##.
15+
##.
16+
17+
1:
18+
###
19+
##.
20+
.##
21+
22+
2:
23+
.##
24+
###
25+
##.
26+
27+
3:
28+
##.
29+
###
30+
##.
31+
32+
4:
33+
###
34+
#..
35+
###
36+
37+
5:
38+
###
39+
.#.
40+
###
41+
42+
4x4: 0 0 0 0 2 0
43+
12x5: 1 0 1 0 2 2
44+
12x5: 1 2 1 5 3 2
45+
""".asList()
46+
47+
"parse presents" {
48+
val input = """
49+
0:
50+
###
51+
##.
52+
##.
53+
54+
1:
55+
###
56+
##.
57+
.##
58+
59+
4x4: 0 0
60+
12x5: 1 0
61+
""".asList()
62+
63+
input.parsePresents() shouldBe Presents(
64+
shapes = listOf(
65+
PresentShape(0, listOf("###", "##.", "##.")),
66+
PresentShape(1, listOf("###", "##.", ".##")),
67+
),
68+
regions = listOf(
69+
Region(4, 4, listOf(0, 0)),
70+
Region(12, 5, listOf(1, 0)),
71+
)
72+
)
73+
}
74+
75+
"PresentShape's number of tiles" {
76+
forAll(
77+
row(listOf("...", "...", "..."), 0),
78+
row(listOf("#.#", ".##", ".#."), 5),
79+
row(listOf("###", "##.", "##."), 7),
80+
row(listOf("###", "###", "###"), 9),
81+
) { input, expected ->
82+
PresentShape(0, input).numberOfTiles shouldBe expected
83+
}
84+
}
85+
86+
"part 1: the number of regions that can fit all of the presents listed" {
87+
ChristmasTreeFarm().part1(input) shouldBe 2
88+
}
89+
90+
"part 2 was to solve all of the year's previous puzzles" {
91+
ChristmasTreeFarm().part2(listOf()) shouldBe 0
92+
}
93+
})

0 commit comments

Comments
 (0)