From c11231307f3af41dbdd1744061c10e62374dc9f7 Mon Sep 17 00:00:00 2001 From: Hubert Van De Walle Date: Tue, 29 Dec 2020 21:09:51 +0100 Subject: [PATCH] Day20 part2 grid assembly --- days/src/main/kotlin/Day20.kt | 114 ++++++++++++++------------ days/src/main/kotlin/geometry/Grid.kt | 7 -- 2 files changed, 63 insertions(+), 58 deletions(-) diff --git a/days/src/main/kotlin/Day20.kt b/days/src/main/kotlin/Day20.kt index f72035d..cd45d88 100644 --- a/days/src/main/kotlin/Day20.kt +++ b/days/src/main/kotlin/Day20.kt @@ -11,10 +11,6 @@ import kotlin.math.sqrt private typealias Tile = Grid -sealed class TileGroup -data class HorizontalGroup(val left: Tile, val right: Tile) : TileGroup() -data class VerticalGroup(val top: Tile, val bottom: Tile) : TileGroup() - @Day(20) class Day20(@Groups val input: Input>>) { private val tiles: Map = input.value @@ -28,20 +24,6 @@ class Day20(@Groups val input: Input>>) { return a.allEdges().any { a -> edges.any { a == it } } } - private fun group(a: Tile, b: Tile): TileGroup? { - for (a: Tile in a.transformations()) { - for (b: Tile in b.transformations()) { - when { - a.firstRow() == b.lastRow() -> return VerticalGroup(top = b, bottom = a) - a.firstColumn() == b.lastColumn() -> return HorizontalGroup(left = b, right = a) - b.firstRow() == a.lastRow() -> return VerticalGroup(top = a, bottom = b) - b.firstColumn() == a.lastColumn() -> return HorizontalGroup(left = a, right = b) - } - } - } - return null - } - private fun combine(tiles: List) = sequence { for (i in 0 until tiles.lastIndex) { val a = tiles[i] @@ -52,7 +34,7 @@ class Day20(@Groups val input: Input>>) { } } - private fun neighbours(): MutableMap> { + private fun tilesByNeighbourCount(): MutableMap> { val neighbours = combine(tiles.values.toList()) .filter { (a, b) -> edgesMatch(a, b) } .map { it.toList() } @@ -67,51 +49,81 @@ class Day20(@Groups val input: Input>>) { return map } - fun part1() = neighbours()[2]!! - .map { tile -> tiles.entries.find { it.value == tile }!!.key.toLong() } - .reduce { acc, id -> acc * id } + fun part1() = tilesByNeighbourCount()[2]!! + .map { tile -> tiles.entries.find { it.value == tile }!!.key.toLong() } + .reduce { acc, id -> acc * id } - fun part2() { + private fun neighboursCount(grid: Grid<*>, x: Int, y: Int): Int { + var neighboursCount = 2 + if (x != 0 && x != grid.lastColumnIndex) neighboursCount++ + if (y != 0 && y != grid.lastRowIndex) neighboursCount++ + return neighboursCount + } + + private fun isLeftOk(grid: Grid, x: Int, y: Int, candidate: Tile) = grid[x - 1, y] + ?.let { left -> candidate.firstColumn() == left.lastColumn() } + ?: true + + private fun isTopOk(grid: Grid, x: Int, y: Int, candidate: Tile) = grid[x, y - 1] + ?.let { top -> candidate.firstRow() == top.lastRow() } + ?: true + + private fun isBottomOk(grid: Grid<*>, x: Int, y: Int, candidate: Tile, neighbours: MutableMap>) = + if (y == grid.lastRowIndex) true + else neighbours[neighboursCount(grid, x, y + 1)]!! + .filterNot { it == candidate } + .count { it.transformations().any { candidate.lastColumn() == it.firstColumn() } } == 1 + + private fun isRightOk(grid: Grid<*>, x: Int, y: Int, candidate: Tile, neighbours: MutableMap>) = + if (x == grid.lastColumnIndex) true + else neighbours[neighboursCount(grid, x + 1, y)]!! + .filterNot { it == candidate } + .count { it.transformations().any { candidate.lastRow() == it.firstRow() } } == 1 + + private fun assembleGrid(): Grid { val size = sqrt(tiles.size.toDouble()).toInt() + val grid: Grid = Grid(Array(size) { Array(size) { null } }) - val n = neighbours() + val neighbours: MutableMap> = tilesByNeighbourCount() - val corners = n[2]!! - .map { tile -> tiles.entries.find { it.value == tile }!!.key.toLong() } + for (y in 0 until grid.height) { + for (x in 0 until grid.width) { + val neighboursCount = neighboursCount(grid, x, y) + val candidates = neighbours[neighboursCount]!! - check(corners.size == 4) + val conditions = mutableListOf<(Tile) -> Boolean>() + conditions += { isLeftOk(grid, x, y, it) } + conditions += { isTopOk(grid, x, y, it) } - val borders = n[3]!! - .map { tile -> tiles.entries.find { it.value == tile }!!.key.toLong() } + // why is this condition needed ? + if (x == 0 && y == 0) { + conditions += { isBottomOk(grid, x, y, it, neighbours) } + conditions += { isRightOk(grid, x, y, it, neighbours) } + } - val insides = n[4]!! - .map { tile -> tiles.entries.find { it.value == tile }!!.key.toLong() } + var found: Tile? = null - val groups = combine(tiles.values.toList()) - .mapNotNull { (a, b) -> group(a, b) } - .toList() + outer@ for (candidate in candidates) { + for (transform in candidate.transformations()) { + if (conditions.all { it(transform) }) { + found = transform + candidates.remove(candidate) + break@outer + } + } + } - val groupValues = groups.flatMap { - when (it) { - is HorizontalGroup -> listOf(it.left, it.right) - is VerticalGroup -> listOf(it.top, it.bottom) + check(found != null) + grid[x, y] = found } } - val gridArray: Array> = Array(size) { Array(size) { null } } - val grid: Grid = Grid(gridArray) + return grid + } - val left = groups.filterIsInstance().map { it.left }.toSet() - val right = groups.filterIsInstance().map { it.right }.toSet() - val top = groups.filterIsInstance().map { it.top }.toSet() - val bottom = groups.filterIsInstance().map { it.bottom }.toSet() - - println("L:${left.size}") - println("R:${right.size}") - println("T:${top.size}") - println("B:${bottom.size}") - - println(groupValues.filter { it in left && it in top && it !in right && it !in bottom }) + fun part2() { + val grid = assembleGrid() + TODO() } } diff --git a/days/src/main/kotlin/geometry/Grid.kt b/days/src/main/kotlin/geometry/Grid.kt index 6f7ebb8..4deb1c6 100644 --- a/days/src/main/kotlin/geometry/Grid.kt +++ b/days/src/main/kotlin/geometry/Grid.kt @@ -44,13 +44,6 @@ class Grid { fun edges() = listOf(row(0), column(0), row(lastRowIndex), column(lastColumnIndex)) - fun neighbours(x: Int, y: Int) = listOf( - x to y - 1, - x + 1 to y, - x to y + 1, - x - 1 to y, - ).mapNotNull { this[x, y] } - override fun toString() = buildString { data.forEach { line -> append(line.joinToString(""))