Skip to content

Instantly share code, notes, and snippets.

@r3domfox
Created December 24, 2020 14:55
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save r3domfox/cfff9b7d0af1897f7ec117495e166cb7 to your computer and use it in GitHub Desktop.
Save r3domfox/cfff9b7d0af1897f7ec117495e166cb7 to your computer and use it in GitHub Desktop.
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