Day 6 part 2 :'-(

Change-Id: I04ba157f88233e3f57632f632c4a60267e486058
This commit is contained in:
Chris Hodges 2024-12-06 12:31:43 +01:00
parent 3cc10ea7c3
commit d2487ed762
2 changed files with 59 additions and 44 deletions

View File

@ -94,6 +94,9 @@ class CharGrid {
if (newChar != null && isInside(col, row)) data[row][col] = newChar if (newChar != null && isInside(col, row)) data[row][col] = newChar
} }
operator fun get(pos: RelPos) = get(pos.dc, pos.dr)
operator fun set(pos: RelPos, newChar: Char?) = set(pos.dc, pos.dr, newChar)
fun setOrThrow(col: Int, row: Int, newChar: Char) { fun setOrThrow(col: Int, row: Int, newChar: Char) {
if (!isInside(col, row)) throw IndexOutOfBoundsException("$col, $row out of bounds") if (!isInside(col, row)) throw IndexOutOfBoundsException("$col, $row out of bounds")
set(col, row, newChar) set(col, row, newChar)
@ -101,12 +104,14 @@ class CharGrid {
fun getOrNull(col: Int, row: Int) = if (isInside(col, row)) data[row][col] else null fun getOrNull(col: Int, row: Int) = if (isInside(col, row)) data[row][col] else null
fun isInside(col: Int, row: Int) = (col in 0 until width) && (row in 0 until height) fun isInside(col: Int, row: Int) = (col in 0 until width) && (row in 0 until height)
fun isInside(pos: RelPos) = isInside(pos.dc, pos.dr)
fun getHorizNumberValueAt(rp: RelPos) = getHorizNumberValueAt(rp.dc, rp.dr) fun getHorizNumberValueAt(rp: RelPos) = getHorizNumberValueAt(rp.dc, rp.dr)
fun getHorizNumberValueAt(col: Int, row: Int): Pair<Int, List<RelPos>> { fun getHorizNumberValueAt(col: Int, row: Int): Pair<Int, List<RelPos>> {
val relPos = getHorizNumberRelPosAt(col, row) val relPos = getHorizNumberRelPosAt(col, row)
return relPos.map { this[col + it.dc, row + it.dr].digitToInt() }.reduce { acc, digit -> acc * 10 + digit } to relPos return relPos.map { this[col + it.dc, row + it.dr].digitToInt() }
.reduce { acc, digit -> acc * 10 + digit } to relPos
} }
fun getHorizNumberRelPosAt(col: Int, row: Int): List<RelPos> { fun getHorizNumberRelPosAt(col: Int, row: Int): List<RelPos> {
@ -159,9 +164,13 @@ class CharGrid {
relposes.map { get(c + it.dc, r + it.dr) } relposes.map { get(c + it.dc, r + it.dr) }
} }
fun countStrings(relposeList: Iterable<Iterable<RelPos>>, string: String) = findMatches(relposeList) { it == string }.count() fun countStrings(relposeList: Iterable<Iterable<RelPos>>, string: String) =
findMatches(relposeList) { it == string }.count()
fun findMatches(relposeList: Iterable<Iterable<RelPos>>, predicate: (content: String) -> Boolean): List<Pair<String, RelPos>> { fun findMatches(
relposeList: Iterable<Iterable<RelPos>>,
predicate: (content: String) -> Boolean
): List<Pair<String, RelPos>> {
val matches = ArrayList<Pair<String, RelPos>>() val matches = ArrayList<Pair<String, RelPos>>()
for (r in 0 until height) { for (r in 0 until height) {
for (c in 0 until width) { for (c in 0 until width) {
@ -176,7 +185,10 @@ class CharGrid {
return matches return matches
} }
fun findCombinedMatches(relposeList: Iterable<Iterable<RelPos>>, predicate: (content: List<String>) -> Boolean): List<RelPos> { fun findCombinedMatches(
relposeList: Iterable<Iterable<RelPos>>,
predicate: (content: List<String>) -> Boolean
): List<RelPos> {
val matches = ArrayList<RelPos>() val matches = ArrayList<RelPos>()
for (r in 0 until height) { for (r in 0 until height) {
for (c in 0 until width) { for (c in 0 until width) {

View File

@ -109,67 +109,70 @@ fun main() {
fun part1(input: List<String>): Int { fun part1(input: List<String>): Int {
val grid = CharGrid(input, '.') val grid = CharGrid(input, '.')
var (c, r) = grid.findMatches { it == '^' }[0] val (oc, or) = grid.findMatches { it == '^' }[0]
var pos = RelPos(oc, or)
var dir = RelPos(0, -1) var dir = RelPos(0, -1)
while (grid.isInside(c, r)) { while (grid.isInside(pos)) {
grid[c, r] = 'X' grid[pos] = 'X'
if (grid[c + dir.dc, r + dir.dr] == '#') { while (grid[pos.translate(dir)] == '#') {
dir = RelPos(-dir.dr, dir.dc) dir = RelPos(-dir.dr, dir.dc)
} }
c += dir.dc pos = pos.translate(dir)
r += dir.dr
} }
return grid.findMatches { it == 'X' }.count() return grid.findMatches { it == 'X' }.count()
} }
fun looping(grid: CharGrid, origDirGrid: Array<IntArray>, oc: Int, or: Int, origDir: RelPos, origDirBit: Int): Boolean { fun checkLooping(grid: CharGrid, origPos: RelPos): Boolean {
val dirgrid = Array(grid.height) { origDirGrid[it].copyOf() } val dirgrid = Array(grid.height) { IntArray(grid.width) }
var dir = origDir var dir = RelPos(0, -1)
var c = oc var dirBit = 0
var r = or var looping = false
var dirBit = origDirBit var pos = origPos
while (grid.isInside(c, r)) { while (grid.isInside(pos)) {
if ((dirgrid[c][r] and (1 shl dirBit)) != 0) { if ((dirgrid[pos.dc][pos.dr] and (1 shl dirBit)) != 0) {
return true looping = true
break
} }
dirgrid[c][r] = dirgrid[c][r] or (1 shl dirBit) dirgrid[pos.dc][pos.dr] = dirgrid[pos.dc][pos.dr] or (1 shl dirBit)
if (grid[c + dir.dc, r + dir.dr] == '#') { while (grid[pos.translate(dir)] == '#') {
dir = RelPos(-dir.dr, dir.dc) dir = RelPos(-dir.dr, dir.dc)
dirBit = (dirBit + 1) and 3 dirBit = (dirBit + 1) and 3
} }
c += dir.dc pos = pos.translate(dir)
r += dir.dr
} }
return false return looping
} }
fun part2(input: List<String>): Int { fun part2(input: List<String>): Int {
val grid = CharGrid(input, '.') val grid = CharGrid(input, '.')
val dirgrid = Array(grid.height) { IntArray(grid.width) } val obstaclePos = HashSet<RelPos>()
var (oc, or) = grid.findMatches { it == '^' }[0] val solutions = HashSet<RelPos>()
var c = oc val (oc, or) = grid.findMatches { it == '^' }[0]
var r = or
var pos = RelPos(oc, or)
var dir = RelPos(0, -1) var dir = RelPos(0, -1)
var dirBit = 0 while (true) {
while (grid.isInside(c, r)) { grid[pos] = 'X'
val newDir = RelPos(-dir.dr, dir.dc) val newPos = pos.translate(dir)
//grid[c, r] = 'X' if (!grid.isInside(newPos)) break
dirgrid[c][r] = dirgrid[c][r] or (1 shl dirBit) if (grid[newPos] == '#') {
if (grid[c + dir.dc, r + dir.dr] == '#') { dir = RelPos(-dir.dr, dir.dc)
dir = newDir
dirBit = (dirBit + 1) and 3
} else { } else {
if (looping(grid, dirgrid, c + newDir.dc, r + newDir.dr, newDir, (dirBit + 1) and 3)) { if (grid[newPos] == '.') {
if ((c + dir.dc != oc) || (r + dir.dr != or)) { obstaclePos.add(newPos)
grid[c + dir.dc, r + dir.dr] = 'O' }
pos = newPos
} }
} }
for (op in obstaclePos) {
grid[op] = '#'
if (checkLooping(grid, RelPos(oc, or))) {
solutions.add(op)
} }
c += dir.dc grid[op] = '.'
r += dir.dr
} }
grid.debug() return solutions.size
return grid.findMatches { it == 'O' }.count()
} }
// test if implementation meets criteria from the description, like: // test if implementation meets criteria from the description, like: