Skip to content

Instantly share code, notes, and snippets.

@sungkmi
Created June 11, 2021 13:07
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 sungkmi/e6947d4e6ffcba65eeaa9842c45dd53c to your computer and use it in GitHub Desktop.
Save sungkmi/e6947d4e6ffcba65eeaa9842c45dd53c to your computer and use it in GitHub Desktop.
package sungkmi.aoc2020.day24
// x: 3 o'clock, y: 1 o'clock
case class D(dx: Int, dy: Int)
object D:
val reference: D = D(0, 0)
extension (d: D)
@annotation.targetName("plus")
def +(other: D): D = D(d.dx + other.dx, d.dy + other.dy)
enum Direction(val d: D):
case E extends Direction(D( 1, 0))
case SE extends Direction(D( 1, -1))
case SW extends Direction(D( 0, -1))
case W extends Direction(D(-1, 0))
case NW extends Direction(D(-1, 1))
case NE extends Direction(D( 0, 1))
def parseLine(line: String): D =
@annotation.tailrec
def loop(xs: List[Char], sum: D): D = xs match
case Nil => sum
case 'e' :: tail => loop(tail, Direction.E.d + sum)
case 's' :: 'e' :: tail => loop(tail, Direction.SE.d + sum)
case 's' :: 'w' :: tail => loop(tail, Direction.SW.d + sum)
case 'w' :: tail => loop(tail, Direction.W.d + sum)
case 'n' :: 'w' :: tail => loop(tail, Direction.NW.d + sum)
case 'n' :: 'e' :: tail => loop(tail, Direction.NE.d + sum)
case _ => throw new Exception(s"Wrong input: ${xs.mkString}")
loop(line.toList, D.reference)
def parse(s: String): Seq[D] = s.split("\n").map(parseLine).toSeq
def findBlackTiles(s: String): Seq[D] = for
(tile, tiles) <- parse(s).groupBy(identity).toSeq
size = tiles.size if size % 2 != 0
yield tile
def solve1(s: String): Int = findBlackTiles(s).size
def step(blackTiles: Set[D]): Set[D] =
val blackNeighbors: Seq[D] = for
blackTile <- blackTiles.toSeq
neighborD <- Direction.values.toSeq
yield blackTile + neighborD.d
val blackNeighborCountMap: Map[D, Int] = blackNeighbors
.groupBy(identity)
.view
.mapValues(_.size)
.toMap
.withDefaultValue(0)
val becomeWhites = blackTiles.filter{ t =>
val neighborCount = blackNeighborCountMap(t)
neighborCount == 0 || neighborCount > 2
}
val becomeBlacks = for
(tile, neighborCount) <- blackNeighborCountMap
if neighborCount == 2 && !blackTiles.contains(tile)
yield tile
blackTiles -- becomeWhites ++ becomeBlacks
def day(n: Int, initialBlackTiles: Set[D]): Set[D] =
(1 to n).foldLeft(initialBlackTiles)((blackTiles, _) => step(blackTiles))
def solve2(s: String): Int = day(100, findBlackTiles(s).toSet).size
@main def part1: Unit =
val ans = solve1(input)
println(ans)
@main def part2: Unit =
val ans = solve2(input)
println(ans)
//lazy val input: String = """wswwwwwwwnenewswnewswwswswww
package sungkmi.aoc2020.day24
class Day24Test extends munit.FunSuite {
val testInput = """sesenwnenenewseeswwswswwnenewsewsw
neeenesenwnwwswnenewnwwsewnenwseswesw
seswneswswsenwwnwse
nwnwneseeswswnenewneswwnewseswneseene
swweswneswnenwsewnwneneseenw
eesenwseswswnenwswnwnwsewwnwsene
sewnenenenesenwsewnenwwwse
wenwwweseeeweswwwnwwe
wsweesenenewnwwnwsenewsenwwsesesenwne
neeswseenwwswnwswswnw
nenwswwsewswnenenewsenwsenwnesesenew
enewnwewneswsewnwswenweswnenwsenwsw
sweneswneswneneenwnewenewwneswswnese
swwesenesewenwneswnwwneseswwne
enesenwswwswneneswsenwnewswseenwsese
wnwnesenesenenwwnenwsewesewsesesew
nenewswnwewswnenesenwnesewesw
eneswnwswnwsenenwnwnwwseeswneewsenese
neswnwewnwnwseenwseesewsenwsweewe
wseweeenwnesenwwwswnew"""
test("day24 parseLine") {
assertEquals(parseLine("esew"), D(1, -1))
assertEquals(parseLine("nwwswee"), D.reference)
}
test("day24 parse") {
val flipCountMap = parse(testInput)
.groupBy(identity)
.view
.mapValues(_.size)
.toSeq
.groupBy(_._2)
.view
.mapValues(_.size)
.toMap
assertEquals(flipCountMap, Map(1 -> 10, 2 -> 5))
}
test("day24 solve1") {
assertEquals(solve1(testInput), 10)
}
test("day24 day") {
val initialBlackTiles: Set[D] = findBlackTiles(testInput).toSet
assertEquals(day(1, initialBlackTiles).size, 15)
assertEquals(day(2, initialBlackTiles).size, 12)
assertEquals(day(3, initialBlackTiles).size, 25)
assertEquals(day(4, initialBlackTiles).size, 14)
assertEquals(day(5, initialBlackTiles).size, 23)
assertEquals(day(6, initialBlackTiles).size, 28)
assertEquals(day(7, initialBlackTiles).size, 41)
assertEquals(day(8, initialBlackTiles).size, 37)
assertEquals(day(9, initialBlackTiles).size, 49)
assertEquals(day(10, initialBlackTiles).size, 37)
assertEquals(day(20, initialBlackTiles).size, 132)
assertEquals(day(30, initialBlackTiles).size, 259)
assertEquals(day(40, initialBlackTiles).size, 406)
assertEquals(day(50, initialBlackTiles).size, 566)
assertEquals(day(60, initialBlackTiles).size, 788)
assertEquals(day(70, initialBlackTiles).size, 1106)
assertEquals(day(80, initialBlackTiles).size, 1373)
assertEquals(day(90, initialBlackTiles).size, 1844)
assertEquals(day(100, initialBlackTiles).size, 2208)
}
test("day24 solve2") {
assertEquals(solve2(testInput), 2208)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment