ok ?
This commit is contained in:
parent
dac50700b6
commit
6689a739bc
@ -1,52 +1,45 @@
|
|||||||
package be.vandewalleh.aoc.days
|
package be.vandewalleh.aoc.days
|
||||||
|
|
||||||
|
import be.vandewalleh.aoc.days.geometry.Grid
|
||||||
|
import be.vandewalleh.aoc.days.geometry.gridOf
|
||||||
|
import be.vandewalleh.aoc.days.geometry.transformations
|
||||||
import be.vandewalleh.aoc.utils.input.Day
|
import be.vandewalleh.aoc.utils.input.Day
|
||||||
import be.vandewalleh.aoc.utils.input.Groups
|
import be.vandewalleh.aoc.utils.input.Groups
|
||||||
import be.vandewalleh.aoc.utils.input.Input
|
import be.vandewalleh.aoc.utils.input.Input
|
||||||
import be.vandewalleh.aoc.utils.input.createDay
|
import be.vandewalleh.aoc.utils.input.createDay
|
||||||
import kotlin.math.sqrt
|
import kotlin.math.sqrt
|
||||||
|
|
||||||
private typealias Tile = Array<CharArray>
|
private typealias Tile = Grid<Char>
|
||||||
private typealias Grid = Array<Array<Tile>>
|
|
||||||
|
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)
|
@Day(20)
|
||||||
class Day20(@Groups val input: Input<List<List<String>>>) {
|
class Day20(@Groups val input: Input<List<List<String>>>) {
|
||||||
|
private val tiles: Map<Int, Tile> = input.value
|
||||||
private val tiles = input.value
|
|
||||||
.map { it[0].let { it.substring(5 until it.indexOf(':')).toInt() } to it.drop(1) }
|
.map { it[0].let { it.substring(5 until it.indexOf(':')).toInt() } to it.drop(1) }
|
||||||
.map { (id, tile) -> id to tile.map { it.toCharArray() }.toTypedArray() }
|
.associate { (id, tile) -> id to gridOf(tile) }
|
||||||
|
|
||||||
private fun Tile.sides() = sequence {
|
private fun Tile.allEdges() = transformations().flatMap { it.edges() }
|
||||||
val tile = this@sides
|
|
||||||
yield(tile[0])
|
private fun edgesMatch(a: Tile, b: Tile): Boolean {
|
||||||
yield(tile[tile.lastIndex])
|
val edges = b.allEdges()
|
||||||
yield(tile[0].reversedArray())
|
return a.allEdges().any { a -> edges.any { a == it } }
|
||||||
yield(tile[tile.lastIndex].reversedArray())
|
|
||||||
yield(tile.map { it[0] }.toCharArray())
|
|
||||||
yield(tile.map { it[tile.lastIndex] }.toCharArray())
|
|
||||||
yield(tile.map { it[0] }.asReversed().toCharArray())
|
|
||||||
yield(tile.map { it[tile.lastIndex] }.asReversed().toCharArray())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun sideMatches(a: Tile, b: Tile): Boolean {
|
private fun group(a: Tile, b: Tile): TileGroup? {
|
||||||
val aSides = a.sides()
|
for (a: Tile in a.transformations()) {
|
||||||
val bSides = b.sides().toList()
|
for (b: Tile in b.transformations()) {
|
||||||
aSides.forEach { aSide ->
|
when {
|
||||||
bSides.forEach { bSide ->
|
a.firstRow() == b.lastRow() -> return VerticalGroup(top = b, bottom = a)
|
||||||
if (aSide contentEquals bSide) return true
|
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 false
|
return null
|
||||||
}
|
|
||||||
|
|
||||||
private fun Tile.prettyPrint() {
|
|
||||||
val str = buildString {
|
|
||||||
this@prettyPrint.forEach { line ->
|
|
||||||
append(line.joinToString(""))
|
|
||||||
appendLine()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
print(str)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun combine(tiles: List<Tile>) = sequence {
|
private fun combine(tiles: List<Tile>) = sequence {
|
||||||
@ -59,12 +52,12 @@ class Day20(@Groups val input: Input<List<List<String>>>) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun neighbours(): Map<Int, List<Tile>> {
|
private fun neighbours(): MutableMap<Int, MutableList<Tile>> {
|
||||||
val neighbours = combine(tiles.map { it.second })
|
val neighbours = combine(tiles.values.toList())
|
||||||
.filter { (a, b) -> sideMatches(a, b) }
|
.filter { (a, b) -> edgesMatch(a, b) }
|
||||||
.map { it.toList() }
|
.map { it.toList() }
|
||||||
.flatten()
|
.flatten()
|
||||||
.groupBy { it.map { it.toList() } }
|
.groupBy { it }
|
||||||
.values
|
.values
|
||||||
|
|
||||||
val map = mutableMapOf<Int, MutableList<Tile>>()
|
val map = mutableMapOf<Int, MutableList<Tile>>()
|
||||||
@ -75,67 +68,52 @@ class Day20(@Groups val input: Input<List<List<String>>>) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun part1() = neighbours()[2]!!
|
fun part1() = neighbours()[2]!!
|
||||||
.map { tile -> tiles.find { it.second === tile }!! }
|
.map { tile -> tiles.entries.find { it.value == tile }!!.key.toLong() }
|
||||||
.map { it.first.toLong() }
|
.reduce { acc, id -> acc * id }
|
||||||
.reduce { acc, id -> acc * id }
|
|
||||||
|
|
||||||
operator fun Array<Array<Tile?>>.get(x: Int, y: Int): Tile? {
|
|
||||||
if (y < 0 || y > lastIndex) return null
|
|
||||||
val row = get(y)
|
|
||||||
|
|
||||||
return if (x < 0 || x > row.lastIndex) null
|
|
||||||
else row[x]
|
|
||||||
}
|
|
||||||
|
|
||||||
operator fun Array<Array<Tile?>>.set(x: Int, y: Int, tile: Tile) {
|
|
||||||
this[y][x] = tile
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun fillGrid(): Grid {
|
|
||||||
val neighboursSet = neighbours().entries.associate { it.key to it.value.toMutableSet() }
|
|
||||||
|
|
||||||
val size = sqrt(tiles.size.toDouble()).toInt()
|
|
||||||
val grid: Array<Array<Tile?>> = Array(size) { Array(size) { null } }
|
|
||||||
|
|
||||||
for (x in 0 until size) {
|
|
||||||
for (y in 0 until size) {
|
|
||||||
var neighboursCount = 2
|
|
||||||
if (x != 0 && x != size - 1) neighboursCount++
|
|
||||||
if (y != 0 && y != size - 1) neighboursCount++
|
|
||||||
|
|
||||||
val pos = listOf(
|
|
||||||
x to y - 1,
|
|
||||||
x + 1 to y,
|
|
||||||
x to y + 1,
|
|
||||||
x - 1 to y,
|
|
||||||
)
|
|
||||||
|
|
||||||
val a = pos.mapNotNull { (x, y) -> grid[x, y] }
|
|
||||||
|
|
||||||
val iterator = neighboursSet[neighboursCount]!!.iterator()
|
|
||||||
|
|
||||||
while (iterator.hasNext()) {
|
|
||||||
val possibility = iterator.next()
|
|
||||||
val matches = a.count { sideMatches(it, possibility) }
|
|
||||||
if (matches == a.size) {
|
|
||||||
grid[x, y] = possibility
|
|
||||||
iterator.remove()
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return grid as Grid
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun correctGrid(grid: Grid): Grid {
|
|
||||||
TODO("flip / rotate every tile")
|
|
||||||
}
|
|
||||||
|
|
||||||
fun part2() {
|
fun part2() {
|
||||||
val grid = correctGrid(fillGrid())
|
val size = sqrt(tiles.size.toDouble()).toInt()
|
||||||
TODO("remove tile edges")
|
|
||||||
|
val n = neighbours()
|
||||||
|
|
||||||
|
val corners = n[2]!!
|
||||||
|
.map { tile -> tiles.entries.find { it.value == tile }!!.key.toLong() }
|
||||||
|
|
||||||
|
check(corners.size == 4)
|
||||||
|
|
||||||
|
val borders = n[3]!!
|
||||||
|
.map { tile -> tiles.entries.find { it.value == tile }!!.key.toLong() }
|
||||||
|
|
||||||
|
val insides = n[4]!!
|
||||||
|
.map { tile -> tiles.entries.find { it.value == tile }!!.key.toLong() }
|
||||||
|
|
||||||
|
val groups = combine(tiles.values.toList())
|
||||||
|
.mapNotNull { (a, b) -> group(a, b) }
|
||||||
|
.toList()
|
||||||
|
|
||||||
|
val groupValues = groups.flatMap {
|
||||||
|
when (it) {
|
||||||
|
is HorizontalGroup -> listOf(it.left, it.right)
|
||||||
|
is VerticalGroup -> listOf(it.top, it.bottom)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val gridArray: Array<Array<Tile?>> = Array(size) { Array(size) { null } }
|
||||||
|
val grid: Grid<Tile?> = Grid(gridArray)
|
||||||
|
|
||||||
|
val left = groups.filterIsInstance<HorizontalGroup>().map { it.left }.toSet()
|
||||||
|
val right = groups.filterIsInstance<HorizontalGroup>().map { it.right }.toSet()
|
||||||
|
val top = groups.filterIsInstance<VerticalGroup>().map { it.top }.toSet()
|
||||||
|
val bottom = groups.filterIsInstance<VerticalGroup>().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 main() {
|
fun main() {
|
||||||
@ -250,6 +228,7 @@ fun main() {
|
|||||||
..#.###...
|
..#.###...
|
||||||
""".trimIndent()
|
""".trimIndent()
|
||||||
)) {
|
)) {
|
||||||
|
println(part1())
|
||||||
println(part2())
|
println(part2())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
71
days/src/main/kotlin/geometry/Grid.kt
Normal file
71
days/src/main/kotlin/geometry/Grid.kt
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
@file:Suppress("MemberVisibilityCanBePrivate")
|
||||||
|
|
||||||
|
package be.vandewalleh.aoc.days.geometry
|
||||||
|
|
||||||
|
class Grid<T> {
|
||||||
|
val data: ArrayList<ArrayList<T>> = ArrayList()
|
||||||
|
|
||||||
|
constructor(data: Iterable<Iterable<T>>) {
|
||||||
|
data.forEach {
|
||||||
|
this.data.add(ArrayList(it.toList()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(data: Array<Array<T>>) {
|
||||||
|
data.forEach {
|
||||||
|
this.data.add(ArrayList(it.toList()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val width get() = data[0].size
|
||||||
|
val lastColumnIndex get() = data[0].size - 1
|
||||||
|
|
||||||
|
val height get() = data.size
|
||||||
|
val lastRowIndex get() = data.size - 1
|
||||||
|
|
||||||
|
operator fun get(x: Int, y: Int): T? {
|
||||||
|
if (y !in 0..lastRowIndex) return null
|
||||||
|
val row = data[y]
|
||||||
|
return if (x !in 0..lastColumnIndex) null
|
||||||
|
else row[x]
|
||||||
|
}
|
||||||
|
|
||||||
|
operator fun set(x: Int, y: Int, value: T) {
|
||||||
|
data[y][x] = value
|
||||||
|
}
|
||||||
|
|
||||||
|
fun row(y: Int): List<T> = data[y]
|
||||||
|
fun firstRow() = row(0)
|
||||||
|
fun lastRow() = row(height - 1)
|
||||||
|
|
||||||
|
fun column(x: Int): List<T> = data.map { it[x] }
|
||||||
|
fun firstColumn() = column(0)
|
||||||
|
fun lastColumn() = column(width - 1)
|
||||||
|
|
||||||
|
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(""))
|
||||||
|
appendLine()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun equals(other: Any?): Boolean {
|
||||||
|
if (this === other) return true
|
||||||
|
if (javaClass != other?.javaClass) return false
|
||||||
|
other as Grid<*>
|
||||||
|
if (data != other.data) return false
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun hashCode() = data.hashCode()
|
||||||
|
|
||||||
|
}
|
||||||
7
days/src/main/kotlin/geometry/GridFactory.kt
Normal file
7
days/src/main/kotlin/geometry/GridFactory.kt
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
package be.vandewalleh.aoc.days.geometry
|
||||||
|
|
||||||
|
fun gridOf(lines: List<String>): Grid<Char> =
|
||||||
|
Grid(lines.map { it.toCharArray().toList() })
|
||||||
|
|
||||||
|
fun gridOf(lines: String): Grid<Char> =
|
||||||
|
gridOf(lines.lines())
|
||||||
53
days/src/main/kotlin/geometry/GridTranformations.kt
Normal file
53
days/src/main/kotlin/geometry/GridTranformations.kt
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
package be.vandewalleh.aoc.days.geometry
|
||||||
|
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
private fun <T> ArrayList<T>.reversed(): ArrayList<T> {
|
||||||
|
val out = ArrayList<T>(this.size)
|
||||||
|
asReversed().forEach { out.add(it) }
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <T> Grid<T>.flipVertically(): Grid<T> = Grid(data.reversed())
|
||||||
|
|
||||||
|
fun <T> Grid<T>.flipHorizontally(): Grid<T> {
|
||||||
|
val out = ArrayList<ArrayList<T>>(height)
|
||||||
|
for (y in 0 until height) {
|
||||||
|
out.add(data[y].reversed())
|
||||||
|
}
|
||||||
|
return Grid(out)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <T> Grid<T>.rotateRight(): Grid<T> {
|
||||||
|
val out = ArrayList<ArrayList<T>>(width)
|
||||||
|
for (x in 0 until width) {
|
||||||
|
out.add(ArrayList<T>(height))
|
||||||
|
for (y in 0 until height) {
|
||||||
|
out[x].add(data[y][x])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Grid(out).flipHorizontally()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <T> Grid<T>.rotateLeft(): Grid<T> {
|
||||||
|
val data = flipHorizontally().data
|
||||||
|
val out = ArrayList<ArrayList<T>>(width)
|
||||||
|
for (x in 0 until width) {
|
||||||
|
out.add(ArrayList<T>(height))
|
||||||
|
for (y in 0 until height) {
|
||||||
|
out[x].add(data[y][x])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Grid(out).flipHorizontally()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <T> Grid<T>.transformations(): Sequence<Grid<T>> = sequence {
|
||||||
|
yield(this@transformations)
|
||||||
|
yield(flipHorizontally())
|
||||||
|
yield(flipVertically())
|
||||||
|
yield(rotateLeft())
|
||||||
|
yield(rotateRight())
|
||||||
|
yield(flipHorizontally().flipVertically())
|
||||||
|
yield(flipVertically().rotateRight())
|
||||||
|
yield(flipVertically().rotateLeft())
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user