Skip to content

Commit

Permalink
2020 day23 (#224)
Browse files Browse the repository at this point in the history
* Initial commit, needs cleanup

* cleanup

* remove notion of counterclockwise link
  • Loading branch information
peckb1 authored Nov 3, 2023
1 parent d550a14 commit 6756cd2
Show file tree
Hide file tree
Showing 4 changed files with 158 additions and 0 deletions.
122 changes: 122 additions & 0 deletions src/main/kotlin/me/peckb/aoc/_2020/calendar/day23/Day23.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
package me.peckb.aoc._2020.calendar.day23

import javax.inject.Inject

import me.peckb.aoc.generators.InputGenerator.InputGeneratorFactory
import java.lang.StringBuilder

class Day23 @Inject constructor(
private val generatorFactory: InputGeneratorFactory,
) {
fun partOne(filename: String) = generatorFactory.forFile(filename).readOne { cupLabeling ->
val cups = mutableMapOf<Int, Cup>()
var currentCup: Cup? = null
var lastCup: Cup? = null

cupLabeling.forEach { cupCodeChar ->
val id = Character.getNumericValue(cupCodeChar)
Cup(id).also { newCup ->
cups[id] = newCup
if (currentCup == null) { currentCup = newCup }
lastCup?.also {
it.clockwiseCup = newCup
}
lastCup = newCup
}
}

lastCup?.also { it.clockwiseCup = currentCup!! }

cups.runGame(100, currentCup!!)

cupOrder(cups).drop(1).dropLast(1)
}

fun partTwo(filename: String) = generatorFactory.forFile(filename).readOne { cupLabeling ->
val cups = mutableMapOf<Int, Cup>()
var currentCup: Cup? = null
var lastCup: Cup? = null

fun setupNewCup (id: Int) {
Cup(id).also { newCup ->
cups[id] = newCup
if (currentCup == null) { currentCup = newCup }
lastCup?.also {
it.clockwiseCup = newCup
}
lastCup = newCup
}
}

cupLabeling.forEach { cupCodeChar -> setupNewCup(Character.getNumericValue(cupCodeChar)) }
lastCup?.also { it.clockwiseCup = currentCup!! }

val previousMaxCup = cups.keys.maxOrNull()!!

repeat(1_000_000 - previousMaxCup) { setupNewCup(previousMaxCup + it + 1) }
lastCup?.also { it.clockwiseCup = currentCup!! }

cups.runGame(10_000_000, currentCup!!)

cups[1]?.clockwiseCup?.id!!.toLong() * cups[1]?.clockwiseCup?.clockwiseCup?.id!!.toLong()
}

private fun Map<Int, Cup>.runGame(rounds: Int, startCup: Cup) {

val allCupIds = keys
val maxCupId = allCupIds.maxOrNull()!!
val minCupId = allCupIds.minOrNull()!!

var currentCup = startCup

repeat(rounds) { round ->
// pick up the next three cups
val firstCupToPickup = currentCup.clockwiseCup
val secondCupToPickup = firstCupToPickup.clockwiseCup
val thirdCupToPickup = secondCupToPickup.clockwiseCup

val cupsInHand = setOfNotNull(firstCupToPickup.id, secondCupToPickup.id, thirdCupToPickup.id)
var destinationCupId = currentCup.id
do {
destinationCupId -= 1
if (destinationCupId < minCupId) destinationCupId = maxCupId
} while(cupsInHand.contains(destinationCupId))

val destinationCup = this[destinationCupId]!!

// from:
// q -> C -> [a, b, c] -> r
// x -> D -> y
val r = thirdCupToPickup.clockwiseCup
val y = destinationCup.clockwiseCup
// to:
// q -> C -> r
// x -> D -> [a, b, c] -> y
currentCup.clockwiseCup = r
destinationCup.clockwiseCup = firstCupToPickup
thirdCupToPickup.clockwiseCup = y

currentCup = currentCup.clockwiseCup
}
}

private fun cupOrder(cups: MutableMap<Int, Cup>): String {
var cup = cups[1]!!
val sb = StringBuilder().apply {
append(cup.id)
}
repeat(cups.size) {
sb.append("${cup.clockwiseCup.id}")
cup = cup.clockwiseCup
}
return sb.toString()
}

data class Cup(val id: Int) {
lateinit var clockwiseCup: Cup

override fun toString(): String {
return id.toString()
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
## [Day 23: Crab Cups](https://adventofcode.com/2020/day/23)
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 @@ -22,6 +22,7 @@ import me.peckb.aoc._2020.calendar.day19.Day19Test
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 javax.inject.Singleton

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

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 Day23Test {
@Inject
lateinit var day23: Day23

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

@Test
fun testDay23PartOne() {
assertEquals("54327968", day23.partOne(DAY_23))
}

@Test
fun testDay23PartTwo() {
assertEquals(157410423276, day23.partTwo(DAY_23))
}

companion object {
private const val DAY_23: String = "advent-of-code-input/2020/day23.input"
}
}

0 comments on commit 6756cd2

Please sign in to comment.