Refactored CharGrid class to use a generator instead of two for-loops. Deprecated old API.
This commit is contained in:
parent
9d61ce1bc4
commit
0876e5c92c
129
src/Utils.kt
129
src/Utils.kt
@ -89,28 +89,37 @@ class CharGrid {
|
|||||||
height = inputGrid.size
|
height = inputGrid.size
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated("Use RelPos version instead")
|
||||||
operator fun get(col: Int, row: Int) = getOrNull(col, row) ?: bChar
|
operator fun get(col: Int, row: Int) = getOrNull(col, row) ?: bChar
|
||||||
|
|
||||||
|
@Deprecated("Use RelPos version instead")
|
||||||
operator fun set(col: Int, row: Int, newChar: Char?) {
|
operator fun set(col: Int, row: Int, newChar: Char?) {
|
||||||
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 get(pos: RelPos) = getOrNull(pos) ?: bChar
|
||||||
operator fun set(pos: RelPos, newChar: Char?) = set(pos.dc, pos.dr, newChar)
|
operator fun set(pos: RelPos, newChar: Char?) {
|
||||||
|
if (newChar != null && isInside(pos)) data[pos.dr][pos.dc] = newChar
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Deprecated("Use RelPos version instead")
|
||||||
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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated("Use RelPos version instead")
|
||||||
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 getOrNull(pos: RelPos) = if (isInside(pos)) data[pos.dr][pos.dc] else null
|
||||||
|
|
||||||
|
@Deprecated("Use RelPos version instead")
|
||||||
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 isInside(pos: RelPos) = (pos.dc in 0 until width) && (pos.dr in 0 until height)
|
||||||
|
|
||||||
fun getHorizNumberValueAt(rp: RelPos) = getHorizNumberValueAt(rp.dc, rp.dr)
|
fun getHorizNumberValueAt(pos: RelPos): Pair<Int, List<RelPos>> {
|
||||||
|
val relPos = getHorizNumberRelPosAt(pos.dc, pos.dr)
|
||||||
fun getHorizNumberValueAt(col: Int, row: Int): Pair<Int, List<RelPos>> {
|
return relPos.map { this[pos.translate(it)].digitToInt() }
|
||||||
val relPos = getHorizNumberRelPosAt(col, row)
|
|
||||||
return relPos.map { this[col + it.dc, row + it.dr].digitToInt() }
|
|
||||||
.reduce { acc, digit -> acc * 10 + digit } to relPos
|
.reduce { acc, digit -> acc * 10 + digit } to relPos
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -127,106 +136,72 @@ class CharGrid {
|
|||||||
|
|
||||||
fun copyOf() = CharGrid(Array(height) { data[it].copyOf() }, borderChar = bChar)
|
fun copyOf() = CharGrid(Array(height) { data[it].copyOf() }, borderChar = bChar)
|
||||||
|
|
||||||
fun applyWithPos(op: (grid: CharGrid, col: Int, row: Int) -> Char?) {
|
fun generateGridPos() = generateSequence(RelPos(0, 0)) {
|
||||||
for (r in 0 until height) {
|
if (it.dc + 1 < width) RelPos(it.dc + 1, it.dr) else if (it.dr + 1 < height) RelPos(0, it.dr + 1) else null
|
||||||
for (c in 0 until width) {
|
|
||||||
this[c, r] = op(this, c, r)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun apply(op: (content: Char) -> Char?) {
|
@Deprecated("Use RelPos version instead")
|
||||||
applyWithPos { grid: CharGrid, col, row -> op(grid[col, row]) }
|
fun applyWithPos(op: (grid: CharGrid, col: Int, row: Int) -> Char?) =
|
||||||
}
|
generateGridPos().forEach { this[it] = op(this, it.dc, it.dr) }
|
||||||
|
|
||||||
|
fun applyWithPos(op: (grid: CharGrid, pos: RelPos) -> Char?) =
|
||||||
|
generateGridPos().forEach { this[it] = op(this, it) }
|
||||||
|
|
||||||
|
fun apply(op: (content: Char) -> Char?) =
|
||||||
|
applyWithPos { grid: CharGrid, pos -> op(grid[pos]) }
|
||||||
|
|
||||||
fun grow(
|
fun grow(
|
||||||
relposes: Iterable<RelPos>, predicate: (content: Char) -> Boolean,
|
relposes: Iterable<RelPos>, predicate: (content: Char) -> Boolean,
|
||||||
op: (orgContent: Char, oldContent: Char, col: Int, row: Int) -> Char? = { orgContent: Char, _: Char, _: Int, _: Int -> orgContent }
|
op: (orgContent: Char, oldContent: Char, pos: RelPos) -> Char? = { orgContent: Char, _: Char, _: RelPos -> orgContent }
|
||||||
): CharGrid {
|
): CharGrid {
|
||||||
val newGrid = copyOf()
|
val newGrid = copyOf()
|
||||||
for (r in 0 until height) {
|
generateGridPos().filter { predicate(get(it)) }
|
||||||
for (c in 0 until width) {
|
.forEach { pos ->
|
||||||
if (predicate(get(c, r))) {
|
relposes
|
||||||
relposes
|
.map { it.translate(pos) }
|
||||||
.map { it.translate(c, r) }
|
.filter { isInside(it) }
|
||||||
.filter { isInside(it.dc, it.dr) }
|
.forEach { newGrid[it] = op(this[pos], newGrid[it], it) }
|
||||||
.forEach { newGrid[it.dc, it.dr] = op(this[c, r], newGrid[it.dc, it.dr], it.dc, it.dr) }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return newGrid
|
return newGrid
|
||||||
}
|
}
|
||||||
|
|
||||||
fun collectRelative(c: Int, r: Int, relposes: Iterable<RelPos>, skipBorder: Boolean = true): List<Char> =
|
fun collectRelative(c: Int, r: Int, relposes: Iterable<RelPos>, skipBorder: Boolean = true): List<Char> =
|
||||||
|
collectRelative(RelPos(c, r), relposes, skipBorder)
|
||||||
|
|
||||||
|
fun collectRelative(pos: RelPos, relposes: Iterable<RelPos>, skipBorder: Boolean = true): List<Char> =
|
||||||
if (skipBorder) {
|
if (skipBorder) {
|
||||||
relposes.mapNotNull { getOrNull(c + it.dc, r + it.dr) }
|
relposes.mapNotNull { getOrNull(pos.translate(it)) }
|
||||||
} else {
|
} else {
|
||||||
relposes.map { get(c + it.dc, r + it.dr) }
|
relposes.map { get(pos.translate(it)) }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun countStrings(relposeList: Iterable<Iterable<RelPos>>, string: String) =
|
fun countStrings(relposeList: Iterable<Iterable<RelPos>>, string: String) =
|
||||||
findMatches(relposeList) { it == string }.count()
|
findMatches(relposeList) { it == string }.count()
|
||||||
|
|
||||||
fun findMatches(
|
fun findMatches(relposeList: Iterable<Iterable<RelPos>>, predicate: (content: String) -> Boolean): List<Pair<String, RelPos>> {
|
||||||
relposeList: Iterable<Iterable<RelPos>>,
|
return generateGridPos().flatMap { pos ->
|
||||||
predicate: (content: String) -> Boolean
|
relposeList.mapNotNull { rp ->
|
||||||
): List<Pair<String, RelPos>> {
|
val st = collectRelative(pos, rp).joinToString("")
|
||||||
val matches = ArrayList<Pair<String, RelPos>>()
|
if (predicate(st)) st to pos else null
|
||||||
for (r in 0 until height) {
|
|
||||||
for (c in 0 until width) {
|
|
||||||
for (rp in relposeList) {
|
|
||||||
val st = collectRelative(c, r, rp).joinToString("")
|
|
||||||
if (predicate(st)) {
|
|
||||||
matches.add(st to RelPos(c, r))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}.toList()
|
||||||
return matches
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun findCombinedMatches(
|
fun findCombinedMatches(relposeList: Iterable<Iterable<RelPos>>, predicate: (content: List<String>) -> Boolean): List<RelPos> {
|
||||||
relposeList: Iterable<Iterable<RelPos>>,
|
return generateGridPos().filter { pos ->
|
||||||
predicate: (content: List<String>) -> Boolean
|
predicate(relposeList.map { rp -> collectRelative(pos, rp).joinToString("") })
|
||||||
): List<RelPos> {
|
}.toList()
|
||||||
val matches = ArrayList<RelPos>()
|
|
||||||
for (r in 0 until height) {
|
|
||||||
for (c in 0 until width) {
|
|
||||||
val str = relposeList.map { collectRelative(c, r, it).joinToString("") }
|
|
||||||
if (predicate(str)) {
|
|
||||||
matches.add(RelPos(c, r))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return matches
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun matchRelative(c: Int, r: Int, relposes: Iterable<RelPos>, predicate: (char: Char) -> Boolean): List<RelPos> =
|
fun matchRelative(c: Int, r: Int, relposes: Iterable<RelPos>, predicate: (char: Char) -> Boolean): List<RelPos> =
|
||||||
relposes.filter { predicate(get(c + it.dc, r + it.dr)) }
|
relposes.filter { predicate(get(c + it.dc, r + it.dr)) }
|
||||||
|
|
||||||
|
|
||||||
fun findMatches(predicate: (char: Char) -> Boolean): List<Pair<Int, Int>> {
|
fun findMatches(predicate: (char: Char) -> Boolean): List<Pair<Int, Int>> {
|
||||||
val matches = ArrayList<Pair<Int, Int>>()
|
return generateGridPos().filter { predicate(get(it)) }.map { it.dc to it.dr }.toList()
|
||||||
for (r in 0 until height) {
|
|
||||||
for (c in 0 until width) {
|
|
||||||
if (predicate(get(c, r))) {
|
|
||||||
matches.add(c to r)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return matches
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun collectMatches(predicate: (char: Char) -> Boolean): List<Pair<Char, RelPos>> {
|
fun collectMatches(predicate: (char: Char) -> Boolean): List<Pair<Char, RelPos>> {
|
||||||
val matches = ArrayList<Pair<Char, RelPos>>()
|
return generateGridPos().filter { predicate(get(it)) }.map { get(it) to it }.toList()
|
||||||
for (r in 0 until height) {
|
|
||||||
for (c in 0 until width) {
|
|
||||||
if (predicate(get(c, r))) {
|
|
||||||
matches.add(get(c, r) to RelPos(c, r))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return matches
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun addBorder(borderChar: Char = bChar): CharGrid {
|
fun addBorder(borderChar: Char = bChar): CharGrid {
|
||||||
|
@ -69,10 +69,10 @@ fun main() {
|
|||||||
symbolGrid.apply { c -> if (!c.isDigit()) c else '.' }
|
symbolGrid.apply { c -> if (!c.isDigit()) c else '.' }
|
||||||
val grownGrid = symbolGrid.grow(CharGrid.BOX_POS, { c -> c != '.' })
|
val grownGrid = symbolGrid.grow(CharGrid.BOX_POS, { c -> c != '.' })
|
||||||
var sum = 0
|
var sum = 0
|
||||||
wholeGrid.applyWithPos { grid, col, row ->
|
wholeGrid.applyWithPos { grid, pos ->
|
||||||
if (grid[col, row].isDigit() && grownGrid[col, row] != '.') {
|
if (grid[pos].isDigit() && grownGrid[pos] != '.') {
|
||||||
val (num, relpos) = grid.getHorizNumberValueAt(col, row)
|
val (num, relpos) = grid.getHorizNumberValueAt(pos)
|
||||||
relpos.forEach { grid[col + it.dc, row + it.dr] = '.' }
|
relpos.forEach { grid[pos.translate(it)] = '.' }
|
||||||
sum += num
|
sum += num
|
||||||
}
|
}
|
||||||
null
|
null
|
||||||
|
@ -100,7 +100,7 @@ fun main() {
|
|||||||
fun part1(input: List<String>, steps: Int): Int {
|
fun part1(input: List<String>, steps: Int): Int {
|
||||||
var grid = CharGrid(input, '#')
|
var grid = CharGrid(input, '#')
|
||||||
for (i in 1..steps) {
|
for (i in 1..steps) {
|
||||||
grid = grid.grow(CharGrid.PLUS_POS, { it == 'S' }, { org: Char, old: Char, _: Int, _: Int ->
|
grid = grid.grow(CharGrid.PLUS_POS, { it == 'S' }, { org: Char, old: Char, _: RelPos ->
|
||||||
if (old != '#') 'O' else old
|
if (old != '#') 'O' else old
|
||||||
})
|
})
|
||||||
grid.apply {
|
grid.apply {
|
||||||
|
@ -132,24 +132,17 @@ fun main() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var sum = 0
|
return grid.generateGridPos().count { pos ->
|
||||||
for (r in 0 until grid.height) {
|
antinodes.any {
|
||||||
for (c in 0 until grid.width) {
|
val rr = pos.dr - it.first.dr
|
||||||
if (antinodes.any {
|
val rc = pos.dc - it.first.dc
|
||||||
val rr = r - it.first.dr
|
val f1 = rr / it.second.dr
|
||||||
val rc = c - it.first.dc
|
val f2 = rc / it.second.dc
|
||||||
val f1 = rr / it.second.dr
|
((rr % it.second.dr) == 0) &&
|
||||||
val f2 = rc / it.second.dc
|
((rc % it.second.dc) == 0) &&
|
||||||
((rr % it.second.dr) == 0) &&
|
(f1 == f2)
|
||||||
((rc % it.second.dc) == 0) &&
|
|
||||||
(f1 == f2)
|
|
||||||
}) {
|
|
||||||
sum++
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return sum
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// test if implementation meets criteria from the description, like:
|
// test if implementation meets criteria from the description, like:
|
||||||
|
Loading…
Reference in New Issue
Block a user