Advent of Code 2021 day 8
12/08/2022, 5:00 AMDan Fingal-Surma
12/08/2022, 5:40 AMDan Fingal-Surma
12/08/2022, 5:40 AMDan Fingal-Surma
12/08/2022, 5:41 AMKiet
12/08/2022, 5:44 AMfun part1(input: List<String>): Unit {
val height = input.size
val width = input.first().length
val grid = input.map { it.map { it.digitToInt() } }
var numVisible = 0
for (h in 0 until height) {
for (w in 0 until width) {
val curr = grid[h][w]
if (w == 0) {
numVisible++
} else if (h == 0) {
numVisible++
} else if (w == width - 1) {
numVisible++
} else if (h == height - 1) {
numVisible++
} else {
val columnValues = grid.map { it[w] }
val leftVisible = grid[h].take(w).all { it < curr }
val rightVisible = grid[h].drop(w + 1).all { it < curr }
val topVisible = columnValues.take(h).all { it < curr }
val bottomVisible = columnValues.drop(h + 1).all { it < curr }
if (leftVisible || rightVisible || topVisible || bottomVisible) {
numVisible++
}
}
}
}
println(numVisible)
}
Part 2:
fun part2(input: List<String>): Unit {
fun <T> List<T>.indexOfLastSequential(predicate: (T) -> Boolean): Int {
val iterator = this.listIterator()
while (iterator.hasNext()) {
if (!predicate(iterator.next())) {
return iterator.previousIndex()
}
}
return size - 1
}
val height = input.size
val width = input.first().length
var highestScenicScore = 0
val grid = input.map { it.map { it.digitToInt() } }
println(grid)
for (h in 0 until height) {
for (w in 0 until width) {
val curr = grid[h][w]
val columnValues = grid.map { it[w] }
val leftIndex = grid[h].take(w).reversed().indexOfLastSequential {
it < curr
}
val rightIndex = grid[h].drop(w + 1).indexOfLastSequential {
it < curr
}
val topIndex = columnValues.take(h).reversed().indexOfLastSequential {
it < curr
}
val bottomIndex = columnValues.drop(h + 1).indexOfLastSequential {
it < curr
}
val indexes = listOf(leftIndex, rightIndex, topIndex, bottomIndex)
val scenicScore = indexes.map {
it + 1
}.reduce { acc, i ->
acc * i
}
highestScenicScore = max(scenicScore, highestScenicScore)
}
}
println(highestScenicScore)
}
Kiet
12/08/2022, 5:45 AMindexOfLast
was returning the index of the last element matching the predicate, not the last index of the element when checking sequentially.Dan Fingal-Surma
12/08/2022, 5:46 AMDan Fingal-Surma
12/08/2022, 5:46 AMvar score1 = 0
for (i in x - 1 downTo 0) {
score1++
if (this[y][i] >= height) break
}
Dan Fingal-Surma
12/08/2022, 5:48 AMtakeWhile { }.size
were indeed not detecting whether or not we hit a tree or the edgexxfast
12/08/2022, 6:01 AMall
and any
mixed up 😂Marcin Wisniowski
12/08/2022, 6:02 AMMarcin Wisniowski
12/08/2022, 6:02 AMDavid Whittaker
12/08/2022, 6:03 AMtakeWhile
to my arsenal for next time!Marcin Wisniowski
12/08/2022, 6:06 AM..<
for the first time in part 1. 😄Neil Banman
12/08/2022, 6:07 AMNeil Banman
12/08/2022, 6:09 AMJonathan Kolberg
12/08/2022, 6:11 AMMichael de Kaste
12/08/2022, 6:38 AMobject Day8 : Challenge() {
val GROW_DIRECTIONS = listOf(-1 to 0, 0 to 1, 1 to 0, 0 to -1)
val parsed = input.lines()
.withIndex()
.flatMap { (y, line) -> line.withIndex().map { (x, value) -> (y to x) to value - '0' } }
.toMap()
val growths = parsed.map { (key, value) -> growOutwards(key.first, key.second, value) }
override fun part1() = growths.count { it.any { (canSee, _) -> canSee } }
override fun part2() = growths.maxOf { growths -> growths.map { it.second }.reduce(Int::times) }
fun growOutwards(sourceY: Int, sourceX: Int, sourceValue: Int) = GROW_DIRECTIONS
.map { (yDif, xDif) ->
generateSequence(sourceY to sourceX) { (y, x) -> y + yDif to x + xDif }
.withIndex()
.drop(1)
.first { !parsed.containsKey(it.value) || parsed.getValue(it.value) >= sourceValue }
.let { (index, value) -> (!parsed.containsKey(value)).let { it to (index - if (it) 1 else 0) } }
}
}
Sergei Petunin
12/08/2022, 6:40 AMtakeWhile
unclogged me, and I managed to come up with this. I still wonder if there is an easier, less-than-cubic time solution to the second part.
fun part2(input: List<String>): Int {
val array = input.map { it.chars().toArray() }.toTypedArray()
return (1 until array.lastIndex).maxOf { i ->
(1 until array.lastIndex).maxOf { j ->
val height = array[i][j]
var left = (i - 1 downTo 0).takeWhile { array[it][j] < height }.size
if (left < i) left++
var right = (i + 1 until array.size).takeWhile { array[it][j] < height }.size
if (right < array.lastIndex - i) right++
var top = (j - 1 downTo 0).takeWhile { array[i][it] < height }.size
if (top < j) top++
var bottom = (j + 1 until array.size).takeWhile { array[i][it] < height }.size
if (bottom < array.lastIndex - j) bottom++
left * right * top * bottom
}
}
}
Jakub Gwóźdź
12/08/2022, 6:49 AMval c = rows[y][x]
val u = (0..y - 1).reversed()
.takeWhile { i -> rows[i][x] < c }
.lastOrNull()
?.let { if (it > 0) y - it + 1 else y }
?: 0
Jan Durovec
12/08/2022, 6:52 AMSequence
operation that would take elements until a condition is met, but include also last element. For part 2 I need to stop at the tree with the same height but still include it and using takeWhile
either stops just before the last or skips past the equally-sized tree. Is there something built-in that would make this shorter?Sergei Petunin
12/08/2022, 6:58 AMfun part1(input: List<String>): Int {
val array = input.map { it.chars().toArray() }.toTypedArray()
val visibility = Array(array.size) {
Array(array[0].size) { false }
}
var count = 0
fun AtomicInteger.updateVisibility(i: Int, j: Int) {
if (array[i][j] > this.get()) {
if (!visibility[i][j]) {
count++
visibility[i][j] = true
}
this.set(array[i][j])
}
}
for (i in array.indices) {
AtomicInteger(-1).apply { array.indices.forEach { updateVisibility(i, it) } }
AtomicInteger(-1).apply { array.indices.reversed().forEach { updateVisibility(i, it) } }
AtomicInteger(-1).apply { array.indices.forEach { updateVisibility(it, i) } }
AtomicInteger(-1).apply { array.indices.reversed().forEach { updateVisibility(it, i) } }
}
return count
}
Kai Yuan
12/08/2022, 7:09 AMindexOfFirst()
for the part2, (takeWhile
could be better):
fun List<List<Int>>.findHighestScore(): Int {
var highScore = 0
for (x in 1 until this[0].lastIndex) {
for (y in 1 until this.lastIndex) {
val myScore = ((x - 1 downTo 0).indexOfFirst { this[it][y] >= this[x][y] }.let { if (it < 0) x else (it + 1) }) *
((x + 1..this[0].lastIndex).indexOfFirst { this[it][y] >= this[x][y] }.let { if (it < 0) this[0].lastIndex - x else (1 + it) }) *
((y - 1 downTo 0).indexOfFirst { this[x][it] >= this[x][y] }.let { if (it < 0) y else (it + 1) }) *
((y + 1..this.lastIndex).indexOfFirst { this[x][it] >= this[x][y] }.let { if (it < 0) this.lastIndex - y else (it + 1) })
highScore = max(highScore, myScore)
}
}
return highScore
}
Dan Fingal-Surma
12/08/2022, 7:22 AMJacob Moulton
12/08/2022, 7:31 AMDan Fingal-Surma
12/08/2022, 7:32 AMChristian Ricardo
12/08/2022, 7:35 AMRiccardo Lippolis
12/08/2022, 7:37 AMtakeWhile { tree <= height }.size
, getting the wrong results. Then realized this fails when you have multiple trees of the same height in a row, where takeWhile will keep counting them even though you need to stop at the first one (maybe this helps others)Dan Fingal-Surma
12/08/2022, 7:40 AMminOf(takeWhile { it.height < height }.size + 1, size)
Neil Banman
12/08/2022, 8:11 AMCoord
class that holds two points and has a bunch of useful functions attached to it. Among these are north, south, east, and west
, which when called without arguments return a Coord
one away from the main one. I would like to create a list like listOf(Coord::north, Coord::south, etc.)
and then apply those functions to my coordinates. But the functions are identified as KFunction4
. Whenever I see any kind K-anything I don't know what to do. I can't seem to refer to them in a function signature. Is there a way to do this?
2. My part1()
function relies on a isVisible()
function, which in turn relies on a directionVisible()
function. What is the rule (if any) on nesting functions? Right now isVisible()
is separate from part1()
, but directionVisible()
is nested within isVisible()
. Should they both be nested? Should neither?
Edit: here's the link: https://github.com/nbanman/Play2022/blob/master/src/main/kotlin/org/gristle/adventOfCode/y2022/d8/Y2022D8.ktDavio
12/08/2022, 8:20 AMDavio
12/08/2022, 8:20 AMDavio
12/08/2022, 8:23 AMtakeWhile
which includes the last element which breaks the condition:
private inline fun <T> Iterable<T>.takeUntil(predicate: (T) -> Boolean): List<T> {
val list = ArrayList<T>()
for (item in this) {
if (predicate(item)) {
list.add(item)
break
}
list.add(item)
}
return list
}
I used it to get the correct number of visible trees from a tree's perspective, at first I just added 1 to everything with takeWhile
but this goes wrong if you hit the edge and still haven't found a larger treePoisonedYouth
12/08/2022, 8:28 AMDavio
12/08/2022, 8:30 AMJan Durovec
12/08/2022, 8:32 AMtakeUntil
returns a List
where as the original takeWhile
returns Iterable
. I.e. the Iterable
content might not necessarily fit to memory. I suggest updating your code to return Iterable
since it's not a complicated change to your code (essentially instead of ArrayList
you wrap your code to Iterable { iterator { ... } }
and use yield
instead of .add()
)Davio
12/08/2022, 8:33 AMDavio
12/08/2022, 8:33 AMDavio
12/08/2022, 8:34 AMtakeWhile
also returns a List, not an IterableJan Durovec
12/08/2022, 8:35 AMDavio
12/08/2022, 8:35 AMDavio
12/08/2022, 8:37 AMpublic fun <T> kotlin.sequences.Sequence<T>.takeWhile(predicate: (T) -> kotlin.Boolean): kotlin.sequences.Sequence<T> { /* compiled code */ }
Davio
12/08/2022, 8:38 AMJan Durovec
12/08/2022, 8:40 AMDavio
12/08/2022, 8:44 AMMichael Böiers
12/08/2022, 9:18 AMpackage aoc2022
fun main() = day08(System.`in`.reader().readLines()).forEach(::println)
private fun day08(input: List<String>): List<Int> {
val H = input.map { it.map(Char::digitToInt) }
fun linesOfSight(x: Int, y: Int) = sequenceOf(
listOf((x - 1 downTo 0), (x + 1 until H[0].size)).map { it.map { x -> x to y } },
listOf((y - 1 downTo 0), (y + 1 until H.size)).map { it.map { y -> x to y } }
).flatten().map { it.map { (x, y) -> H[y][x] } }
fun List<Int>.isVisible(h: Int) = all { it < h }
fun List<Int>.countVisible(h: Int) = indexOfFirst { it >= h }.let { if (it == -1) size else it + 1 }
return with(H.flatMapIndexed { y, l -> l.mapIndexed { x, h -> Triple(x, y, h) } }) {
listOf(
count { (x, y, h) -> linesOfSight(x, y).any { it.isVisible(h) } },
maxOf { (x, y, h) -> linesOfSight(x, y).map { it.countVisible(h) }.reduce(Int::times) }
)
}
}
frascu
12/08/2022, 9:39 AMAnders Kirkeby
12/08/2022, 9:44 AMDavio
12/08/2022, 9:46 AMDavio
12/08/2022, 9:47 AMMichael Böiers
12/08/2022, 10:24 AMAnirudh
12/08/2022, 10:38 AM<
height followed by a if-not-last-index, add 1 (edge vs non-edge).
I also went with a Sequence of Ranges for the lines of sight, but did not map them to tree heights. reversing the order the left & top trees for part 2 was just adding a .reversed()
. maybe will put it in "utils" for future puzzles.
https://github.com/aneroid/advent-of-code-2022-kotlin/blob/main/src/Day08.ktxxfast
12/08/2022, 10:48 AMephemient
12/08/2022, 11:24 AMMichael Böiers
12/08/2022, 12:25 PMSimon Birt
12/08/2022, 1:10 PMOzioma Ogbe
12/08/2022, 1:36 PMritesh
12/08/2022, 2:20 PMchiroptical
12/08/2022, 2:20 PMMichael Böiers
12/08/2022, 2:21 PMchiroptical
12/08/2022, 2:23 PMMichael Böiers
12/08/2022, 2:31 PMchiroptical
12/08/2022, 2:33 PMritesh
12/08/2022, 2:33 PMMichael Böiers
12/08/2022, 2:38 PMDavio
12/08/2022, 2:39 PMDavio
12/08/2022, 2:41 PMMichael Böiers
12/08/2022, 2:51 PMDavio
12/08/2022, 3:03 PMritesh
12/08/2022, 3:05 PMphldavies
12/08/2022, 3:22 PMFredrik Rødland
12/08/2022, 4:02 PMx,y
and keep track of them to avoid counting them twice I guess.todd.ginsberg
12/08/2022, 4:10 PMIterable<Int>.product()
and Iterable<T>.takeUntil()
• Blog
• CodeFredrik Rødland
12/08/2022, 4:11 PMtakeUntil
as well
ended up with this:
private fun List<Pos>.scenicScore(intGrid: IntGrid, value: Int): Int {
val idx = indexOfFirst { intGrid[it] >= value } + 1
return if (idx == 0) size else idx
}
todd.ginsberg
12/08/2022, 4:12 PMindexOfFirst
exists. Doh!Paul Woitaschek
12/08/2022, 4:43 PMphldavies
12/08/2022, 4:46 PMIterable<Int>.product()
can also be written as reduce(Int::times)
😉todd.ginsberg
12/08/2022, 4:59 PMKarloti
12/08/2022, 4:59 PMfun part1(a: Array<IntArray>): Int {
val n = a.size
val m = a[0].size
val b = Array(n) { BooleanArray(m) }
var hIndex: Int
var h1: Int
var h2: Int
for (i in 0 until n) {
hIndex = 0
h1 = -1
for (j in 0 until m) {
if (a[i][j] > h1) {
h1 = a[i][j]
hIndex = j
b[i][j] = true
} else if (h1 == 9) break
}
h2 = -1
for (j in m - 1 downTo hIndex) {
if (a[i][j] > h2) {
if (h1 == h2) break
h2 = a[i][j]
b[i][j] = true
}
}
}
for (j in 0 until m) {
hIndex = 0
h1 = -1
for (i in 0 until n) {
if (a[i][j] > h1) {
h1 = a[i][j]
hIndex = i
b[i][j] = true
} else if (h1 == 9) break
}
h2 = -1
for (i in n - 1 downTo hIndex) {
if (a[i][j] > h2) {
if (h1 == h2) break
h2 = a[i][j]
b[i][j] = true
}
}
}
var count = 2 * m + 2 * n - 4
for (i in 1 until n - 1)
for (j in 1 until m - 1)
if (b[i][j]) count++
return count
}
kenkyee
12/08/2022, 5:45 PMphldavies
12/08/2022, 5:47 PM[1] [3] 3 3 [5] 5 5 2
are the seen trees, I believephldavies
12/08/2022, 5:48 PM0
so can always see the first treekenkyee
12/08/2022, 5:49 PMkenkyee
12/08/2022, 5:49 PM2L * rowSize + 2 * colSize - 4
phldavies
12/08/2022, 5:49 PM[1] [3] 3 3 [5] 5 [5] [2]
would be all seen in that row (both from left and right)Venkataramanan Parameswaran
12/08/2022, 6:32 PMKarloti
12/08/2022, 6:54 PMGrzegorz Aniol
12/08/2022, 6:59 PMphldavies
12/08/2022, 7:26 PMGrzegorz Aniol
12/08/2022, 10:30 PMxxfast
12/08/2022, 10:37 PMYann Le Gall
12/09/2022, 3:58 AM