Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Day 24 2020 #225

Merged
merged 1 commit into from
Nov 10, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
132 changes: 132 additions & 0 deletions src/main/kotlin/me/peckb/aoc/_2020/calendar/day24/Day24.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
package me.peckb.aoc._2020.calendar.day24

import me.peckb.aoc._2020.calendar.day24.Day24.Step.*
import me.peckb.aoc._2020.calendar.day24.Day24.TileColor.*
import javax.inject.Inject

import me.peckb.aoc.generators.InputGenerator.InputGeneratorFactory

class Day24 @Inject constructor(
private val generatorFactory: InputGeneratorFactory,
) {
fun partOne(filename: String) = generatorFactory.forFile(filename).readAs(::tilePath) { input ->
val flippedTiles = initialTileLayout(input)
flippedTiles.count { it.value == BLACK }
}

fun partTwo(filename: String) = generatorFactory.forFile(filename).readAs(::tilePath) { input ->
val flippedTiles = initialTileLayout(input)

repeat(100) {
val tilesToFlip = mutableSetOf<Location>()
flippedTiles
.filter { flippedTiles.getOrDefault(it.key, WHITE) == BLACK }
.flatMap { it.key.neighborLocations.plus(it.key) }
.forEach { location ->
val color = flippedTiles.getOrDefault(location, WHITE)
val neighbors = location.neighborLocations
val blackNeighborTileCount = neighbors.mapNotNull { flippedTiles[it] }.count { it == BLACK }

when (color) {
BLACK -> if (0 == blackNeighborTileCount || 2 < blackNeighborTileCount) tilesToFlip.add(location)
WHITE -> if (2 == blackNeighborTileCount) tilesToFlip.add(location)
}
}
tilesToFlip.forEach {
flippedTiles[it] = flippedTiles.getOrDefault(it, WHITE).flip()
}
}

flippedTiles.count { it.value == BLACK }
}

private fun initialTileLayout(input: Sequence<List<Step>>): MutableMap<Location, TileColor> {
val flippedTiles = mutableMapOf<Location, TileColor>()

input.forEach { steps ->
var x = 0
var y = 0
var z = 0

steps.forEach { step ->
when (step) {
// East / West don't change the Z
// North East / South West don't change the Y
// South East / North West don't change the X
EAST -> { x += 1; y -= 1 }
WEST -> { x -= 1; y += 1 }
NORTH_EAST -> { x += 1; z -= 1 }
SOUTH_WEST -> { x -= 1; z += 1 }
SOUTH_EAST -> { y -= 1; z += 1 }
NORTH_WEST -> { y += 1; z -= 1 }
}
}

val location = Location(x, y, z)

flippedTiles[location] = flippedTiles.getOrDefault(location, WHITE).flip()
}

return flippedTiles
}

private fun tilePath(line: String): List<Step> {
val iterator = line.iterator()
val steps = mutableListOf<Step>()

while(iterator.hasNext()) {
steps.add(
when (val d = iterator.nextChar()) {
'e' -> EAST
'w'-> WEST
's' -> {
when (val d2 = iterator.nextChar()) {
'e' -> SOUTH_EAST
'w' -> SOUTH_WEST
else -> throw IllegalStateException("Invalid Step End: $d2")
}
}
'n' -> {
when (val d2 = iterator.nextChar()) {
'e' -> NORTH_EAST
'w' -> NORTH_WEST
else -> throw IllegalStateException("Invalid Step End: $d2")
}
}
else -> throw IllegalStateException("Invalid Step Start: $d")
}
)
}

return steps
}

enum class Step {
// e, se, sw, w, nw, and ne
EAST, SOUTH_EAST, SOUTH_WEST, WEST, NORTH_WEST, NORTH_EAST
}

data class Location(
val x: Int,
val y: Int,
val z: Int,
) {
val neighborLocations by lazy {
listOf(
Location(x + 1, y - 1, z),
Location(x - 1, y + 1, z),
Location(x + 1, y, z - 1),
Location(x - 1, y, z + 1),
Location(x, y - 1, z + 1),
Location(x, y + 1, z - 1),
)
}
}

enum class TileColor {
BLACK { override fun flip(): TileColor = WHITE },
WHITE { override fun flip(): TileColor = BLACK };

abstract fun flip(): TileColor
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
## [Day 24: Lobby Layout](https://adventofcode.com/2020/day/24)
2 changes: 2 additions & 0 deletions src/test/kotlin/me/peckb/aoc/_2020/TestDayComponent.kt
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import me.peckb.aoc._2020.calendar.day20.Day20Test
import me.peckb.aoc._2020.calendar.day21.Day21Test
import me.peckb.aoc._2020.calendar.day22.Day22Test
import me.peckb.aoc._2020.calendar.day23.Day23Test
import me.peckb.aoc._2020.calendar.day24.Day24Test
import javax.inject.Singleton

import me.peckb.aoc.DayComponent
Expand Down Expand Up @@ -55,4 +56,5 @@ internal interface TestDayComponent : DayComponent {
fun inject(day21Test: Day21Test)
fun inject(day22Test: Day22Test)
fun inject(day23Test: Day23Test)
fun inject(day24Test: Day24Test)
}
33 changes: 33 additions & 0 deletions src/test/kotlin/me/peckb/aoc/_2020/calendar/day24/Day24Test.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package me.peckb.aoc._2020.calendar.day24

import javax.inject.Inject


import me.peckb.aoc._2020.DaggerTestDayComponent
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test

internal class Day24Test {
@Inject
lateinit var day24: Day24

@BeforeEach
fun setup() {
DaggerTestDayComponent.create().inject(this)
}

@Test
fun testDay24PartOne() {
assertEquals(312, day24.partOne(DAY_24))
}

@Test
fun testDay24PartTwo() {
assertEquals(3733, day24.partTwo(DAY_24))
}

companion object {
private const val DAY_24: String = "advent-of-code-input/2020/day24.input"
}
}
Loading