Skip to content

Commit

Permalink
Solve day 12 part 1
Browse files Browse the repository at this point in the history
  • Loading branch information
Stannislav committed Dec 13, 2024
1 parent def510a commit b073979
Show file tree
Hide file tree
Showing 2 changed files with 111 additions and 0 deletions.
60 changes: 60 additions & 0 deletions aoc2024/src/main/kotlin/day12/Day12.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package day12

import common.*
import java.io.File
import java.io.InputStream
import java.util.LinkedList
import java.util.Queue
import kotlin.streams.asSequence

fun main() {
val input = parseInput(File("input/12.txt").inputStream())
println("Part 1: ${part1(input)}")
}

fun parseInput(stream: InputStream): Map<Vec, Char> {
return stream
.bufferedReader()
.lines()
.asSequence()
.flatMapIndexed { i, line -> line.mapIndexed { j, c -> Vec(i, j) to c }}
.toMap()
}

fun findRegionFor(pos: Vec, map: Map<Vec, Char>): Set<Vec> {
val regionChar = map[pos] ?: error("$pos not in map")
val region = mutableSetOf(pos)
val q: Queue<Vec> = LinkedList<Vec>().apply { add(pos) }
while (q.isNotEmpty()) {
val v = q.remove()
sequenceOf(Vec(1, 0), Vec(0, 1), Vec(-1, 0), Vec(0, -1))
.map { v + it }
.filter { !region.contains(it) && map.getOrDefault(it, '?') == regionChar }
.forEach { q.add(it); region.add(it) }
}
return region
}

fun getRegions(map: Map<Vec, Char>): List<Set<Vec>> {
val seen = mutableSetOf<Vec>()
val regions = mutableListOf<Set<Vec>>()
map.keys.forEach {
if (!seen.contains(it)) {
val region = findRegionFor(it, map)
regions.add(region)
seen.addAll(region)
}
}

return regions
}

fun part1(input: Map<Vec, Char>): Int {
return getRegions(input).sumOf { it.size * it.sumOf { pos -> perimeterScore(pos, input) }}
}

fun perimeterScore(pos: Vec, input: Map<Vec, Char>): Int {
val map = input.withDefault { '?' }
return sequenceOf(Vec(1, 0), Vec(0, 1), Vec(-1, 0), Vec(0, -1))
.count { map.getValue(pos) != map.getValue(pos + it) }
}
51 changes: 51 additions & 0 deletions aoc2024/src/test/kotlin/Day12Test.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import common.Vec
import day12.parseInput
import day12.part1
import kotlin.test.Test
import kotlin.test.assertEquals

class Day12Test {
private val input1 = """
AAAA
BBCD
BBCC
EEEC
""".trimIndent()
private val input2 = """
OOOOO
OXOXO
OOOOO
OXOXO
OOOOO
""".trimIndent()
private val input3 = """
RRRRIICCFF
RRRRIICCCF
VVRRRCCFFF
VVRCCCJFFF
VVVVCJJCFE
VVIVCCJJEE
VVIIICJJEE
MIIIIIJJEE
MIIISIJEEE
MMMISSJEEE
""".trimIndent()

@Test
fun `Should parse input correctly`() {
val expected = mapOf(
Vec(0, 0) to 'A', Vec(0, 1) to 'A',Vec(0, 2) to 'A',Vec(0, 3) to 'A',
Vec(1, 0) to 'B', Vec(1, 1) to 'B',Vec(1, 2) to 'C',Vec(1, 3) to 'D',
Vec(2, 0) to 'B', Vec(2, 1) to 'B',Vec(2, 2) to 'C',Vec(2, 3) to 'C',
Vec(3, 0) to 'E', Vec(3, 1) to 'E',Vec(3, 2) to 'E',Vec(3, 3) to 'C',
)
assertEquals(expected, parseInput(input1.byteInputStream()))
}

@Test
fun testPart1() {
// assertEquals(140, part1(parseInput(input1.byteInputStream())))
assertEquals(772, part1(parseInput(input2.byteInputStream())))
assertEquals(1930, part1(parseInput(input3.byteInputStream())))
}
}

0 comments on commit b073979

Please sign in to comment.