Created
December 24, 2020 14:55
-
-
Save r3domfox/cfff9b7d0af1897f7ec117495e166cb7 to your computer and use it in GitHub Desktop.
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 hexagons() { | |
val pathStrings = "hexagons.txt".asResource { it.split("\n") } | |
// Convert the path strings into lists of pairs of (dx, dy) | |
fun parsePathSegment(input: String, pos: Int): Pair<Int, Pair<Int, Int>> = when(input[pos]) { | |
'e' -> (pos + 1) to (2 to 0) | |
'w' -> (pos + 1) to (-2 to 0) | |
'n' -> when(input[pos + 1]) { | |
'e' -> (pos + 2) to (1 to 1) | |
'w' -> (pos + 2) to (-1 to 1) | |
else -> throw IllegalArgumentException("Unexpected character ${input[pos + 1]}") | |
} | |
's' -> when(input[pos + 1]) { | |
'e' -> (pos + 2) to (1 to -1) | |
'w' -> (pos + 2) to (-1 to -1) | |
else -> throw IllegalArgumentException("Unexpected character ${input[pos + 1]}") | |
} | |
else -> throw IllegalArgumentException("Unexpected character ${input[pos]}") | |
} | |
fun parsePath(path: String): List<Pair<Int, Int>> { | |
var pos = 0 | |
val result = mutableListOf<Pair<Int, Int>>() | |
while (pos < path.length) { | |
val (newPos, segment) = parsePathSegment(path, pos) | |
pos = newPos | |
result.add(segment) | |
} | |
return result | |
} | |
val paths = pathStrings.map { parsePath(it) } | |
// Toggle set membership of targeted tiles | |
val blackTiles = paths.fold(emptySet<Pair<Int, Int>>()) { squares, path -> | |
val target = path.fold(0 to 0) { (x, y), (dx, dy) -> | |
(x + dx) to (y + dy) | |
} | |
if (target in squares) squares - target else squares + target | |
} | |
// Result of the first part | |
println(blackTiles.size) | |
// Function giving the co-ordinates of tiles adjacent to a given tile | |
fun adjacentTiles(x: Int, y: Int): Sequence<Pair<Int, Int>> = sequenceOf( | |
x - 1 to y + 1, | |
x + 1 to y + 1, | |
x - 2 to y, | |
x + 2 to y, | |
x - 1 to y - 1, | |
x + 1 to y - 1 | |
) | |
// Functions finding all the neighbour tiles of tiles in a set of tiles | |
fun neighbours(tiles: Set<Pair<Int, Int>>): Set<Pair<Int, Int>> = tiles.asSequence().flatMap { (x, y) -> | |
adjacentTiles(x, y) | |
}.toSet() - tiles | |
// Function from a set of black tile co-ordinates to a set of black tile co-ordinates | |
fun flip(tiles: Set<Pair<Int, Int>>): Set<Pair<Int, Int>> { | |
val blacksToWhite = tiles.filter { (x, y) -> | |
adjacentTiles(x, y).count { it in tiles } !in 1..2 | |
} | |
val whitesToBlack = neighbours(tiles).filter { (x, y) -> | |
adjacentTiles(x, y).count { it in tiles} == 2 | |
} | |
return tiles + whitesToBlack - blacksToWhite | |
} | |
// Run the flip function 100 times against the black tiles | |
val result = (1..100).fold(blackTiles) { tiles, _ -> flip(tiles) } | |
// Result of part 2 | |
println(result.size) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment