Last active
August 29, 2020 22:05
-
-
Save saidaspen/3f5312f78f3ac222555797c391afa1bd to your computer and use it in GitHub Desktop.
Advent of Code 2017 Day 21
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
fun main() { | |
val input = java.io.File(ClassLoader.getSystemResource("201721").file).readText().trim() | |
println("Part 1: " + Day21().part1(input, 5)) | |
println("Part 2: " + Day21().part1(input, 18)) | |
} | |
typealias G = Grid<Char> | |
typealias P<A, B> = Pair<A, B> | |
class Day21 { | |
fun part1(input: String, iterations: Int): Int { | |
val rules = input.lines() | |
.filter { it != "" } | |
.map { it.split("=>") } | |
.map { P(toGrid(it[0].trim()), toGrid(it[1].trim())) } | |
.flatMap { variants(it.first).map { r -> Pair(r, it.second) } } | |
.map { it.first.toString() to it.second } | |
.toMap() | |
return (0 until iterations).fold(toGrid(".#./..#/###")) { acc, _ -> | |
reconstruct(deconstruct(acc).mapElements { rules[it.toString()]!! }) | |
}.map { if (it == '#') 1 else 0 }.sum() | |
} | |
private fun reconstruct(parts: Grid<G>): G { | |
if (parts.size() == 1) return parts[0, 0] | |
return (0 until parts.height).fold(G()) { acc, rowIdx -> | |
acc.appendBelow(parts[rowIdx].reduce { row, elem -> row.appendRight(elem) }) | |
} | |
} | |
fun deconstruct(grid: G): Grid<G> { | |
val chunkSize = if (grid.width % 2 == 0) 2 else 3 | |
val numChunks = grid.width / chunkSize | |
return if (numChunks == 1) gridFrom(grid) | |
else Grid((0 until numChunks).map { row -> | |
(0 until numChunks).map { col -> | |
grid.subGrid(row * chunkSize, col * chunkSize, chunkSize, chunkSize) | |
}.toList() | |
}.toList()) | |
} | |
private fun variants(g: G): List<G> = listOf(g, g.flipH(), g.flipV()).flatMap { rotations(it) }.distinct() | |
private fun rotations(g: G): List<G> = listOf(g, g.rotateCw(1), g.rotateCw(2), g.rotateCw(3)) | |
private fun toGrid(s: String): G = G(s.split("/").map { it.toCharArray().toList() }) | |
} | |
class Grid<T> { | |
val width by lazy { if (grid.size == 0) 0 else grid[0].size } | |
val height by lazy { grid.size } | |
fun size(): Int = width * height | |
constructor() { grid = mutableListOf() } | |
private var grid: MutableList<MutableList<T>> | |
constructor(map: List<List<T>>) { grid = map.map { it.toMutableList() }.toMutableList() } | |
fun flipV(): Grid<T> = Grid(grid.reversed().map { it }) | |
fun flipH(): Grid<T> = Grid(grid.map { it.reversed() }) | |
operator fun get(row: Int, col: Int): T = grid[row][col] | |
operator fun get(i: Int): List<T> = grid[i] | |
fun <G> map(function: (T) -> G): List<G> = grid.flatten().map(function) | |
fun <G> mapElements(function: (T) -> G): Grid<G> = Grid(grid.map { it.map(function) }) | |
override fun toString(): String = "[" + grid.joinToString("/") { it.joinToString("") } + "]" | |
fun rotateCw(i: Int): Grid<T> = Grid(rotateCw(grid, i)) | |
private fun rotateCw(rows: MutableList<MutableList<T>>, rotations: Int): MutableList<MutableList<T>> { | |
if (grid.size == 0) return grid | |
val nGrid = mutableListOf<MutableList<T>>() | |
for (iCol in 0 until grid[0].size) { | |
val row = mutableListOf<T>() | |
for (iRow in grid.size - 1 downTo 0) row.add(rows[iRow][iCol]) | |
nGrid.add(row) | |
} | |
return if (rotations == 1) nGrid else rotateCw(nGrid, rotations - 1) | |
} | |
fun subGrid(y: Int, x: Int, height: Int, width: Int): Grid<T> = Grid((y until y + height).map { grid[it].subList(x, x + width) }.toList()) | |
fun appendRight(right: Grid<T>): Grid<T> = Grid((0 until grid.size).map { listOf(grid[it], right[it]).flatten() }.toList()) | |
fun appendBelow(below: Grid<T>): Grid<T> = Grid(listOf(grid, below.grid).flatten()) | |
} | |
fun <T> gridFrom(map: T): Grid<T> = Grid(listOf(listOf(map))) | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment