143 lines
4.1 KiB
Kotlin
143 lines
4.1 KiB
Kotlin
package aoc2023
|
|
|
|
import CharGrid
|
|
import println
|
|
import readInput
|
|
|
|
/*
|
|
--- Day 13: Point of Incidence ---
|
|
https://adventofcode.com/2023/day/13
|
|
*/
|
|
fun main() {
|
|
|
|
val inlineTestInput = """
|
|
#.##..##.
|
|
..#.##.#.
|
|
##......#
|
|
##......#
|
|
..#.##.#.
|
|
..##..##.
|
|
#.#.##.#.
|
|
|
|
#...##..#
|
|
#....#..#
|
|
..##..###
|
|
#####.##.
|
|
#####.##.
|
|
..##..###
|
|
#....#..#
|
|
"""
|
|
|
|
fun mirrored(bits: IntArray, size: Int): Int {
|
|
for (p1 in 0 until size - 1) {
|
|
var p2 = 0
|
|
var match = true
|
|
while (p1 >= p2 && p1 + p2 + 1 < size) {
|
|
if (bits[p1 - p2] != bits[p1 + p2 + 1]) {
|
|
match = false
|
|
break
|
|
}
|
|
p2++
|
|
}
|
|
if (match) return p1 + 1
|
|
}
|
|
return 0
|
|
}
|
|
|
|
fun smudged(bits: IntArray, size: Int): Int {
|
|
for (p1 in 0 until size - 1) {
|
|
var smudges = 0
|
|
var p2 = 0
|
|
while (p1 >= p2 && p1 + p2 + 1 < size) {
|
|
smudges += (bits[p1 - p2] xor bits[p1 + p2 + 1]).countOneBits()
|
|
if (smudges > 1) break
|
|
p2++
|
|
}
|
|
if (smudges == 1) return p1 + 1
|
|
}
|
|
return 0
|
|
}
|
|
|
|
fun part1(input: List<String>): Int {
|
|
val tmpList = ArrayList<String>()
|
|
var result = 0
|
|
for ((idx, i) in input.withIndex()) {
|
|
if (i.isNotBlank()) {
|
|
tmpList.add(i)
|
|
}
|
|
if (i.isBlank() || (idx == input.lastIndex && tmpList.isNotEmpty())) {
|
|
val grid = CharGrid(tmpList)
|
|
val vertSA = IntArray(grid.width)
|
|
val horzSA = IntArray(grid.height)
|
|
for (c in 0 until grid.width) {
|
|
for (r in 0 until grid.height) {
|
|
vertSA[c] = vertSA[c] * 2 + (if (grid[c, r] == '#') 1 else 0)
|
|
}
|
|
}
|
|
for (r in 0 until grid.height) {
|
|
for (c in 0 until grid.width) {
|
|
horzSA[r] = horzSA[r] * 2 + if (grid[c, r] == '#') 1 else 0
|
|
}
|
|
}
|
|
val vref = mirrored(vertSA, grid.width)
|
|
if (vref > 0) {
|
|
result += vref
|
|
} else {
|
|
result += mirrored(horzSA, grid.height) * 100
|
|
}
|
|
|
|
tmpList.clear()
|
|
}
|
|
}
|
|
return result
|
|
}
|
|
|
|
fun part2(input: List<String>): Int {
|
|
val tmpList = ArrayList<String>()
|
|
var result = 0
|
|
for ((idx, i) in input.withIndex()) {
|
|
if (i.isNotBlank()) {
|
|
tmpList.add(i)
|
|
}
|
|
if (i.isBlank() || (idx == input.lastIndex && tmpList.isNotEmpty())) {
|
|
val grid = CharGrid(tmpList)
|
|
val vertSA = IntArray(grid.width)
|
|
val horzSA = IntArray(grid.height)
|
|
for (c in 0 until grid.width) {
|
|
for (r in 0 until grid.height) {
|
|
vertSA[c] = vertSA[c] * 2 + (if (grid[c, r] == '#') 1 else 0)
|
|
}
|
|
}
|
|
for (r in 0 until grid.height) {
|
|
for (c in 0 until grid.width) {
|
|
horzSA[r] = horzSA[r] * 2 + if (grid[c, r] == '#') 1 else 0
|
|
}
|
|
}
|
|
val vref = smudged(vertSA, grid.width)
|
|
if (vref > 0) {
|
|
result += vref
|
|
} else {
|
|
result += smudged(horzSA, grid.height) * 100
|
|
}
|
|
|
|
tmpList.clear()
|
|
}
|
|
}
|
|
return result
|
|
}
|
|
|
|
// test if implementation meets criteria from the description, like:
|
|
val testInput = inlineTestInput.trim().reader().readLines()
|
|
//val testInput = readInput("aoc2023/Day13_test")
|
|
val testInputPart1Result = part1(testInput)
|
|
println("Part 1 Test: $testInputPart1Result")
|
|
val testInputPart2Result = part2(testInput)
|
|
println("Part 2 Test: $testInputPart2Result")
|
|
check(testInputPart1Result == 405)
|
|
check(testInputPart2Result == 400)
|
|
|
|
val input = readInput("aoc2023/Day13")
|
|
part1(input).println()
|
|
part2(input).println()
|
|
}
|