1
0

Compare commits

...

2 Commits

Author SHA1 Message Date
d793a47801 Day23 part2 2020-12-23 18:09:30 +01:00
ff798eaffb Day23 part1 2020-12-23 11:26:02 +01:00
2 changed files with 119 additions and 0 deletions

View File

@ -0,0 +1,118 @@
package be.vandewalleh.aoc.days
import be.vandewalleh.aoc.utils.input.Day
import be.vandewalleh.aoc.utils.input.Input
import be.vandewalleh.aoc.utils.input.Text
import be.vandewalleh.aoc.utils.input.createDay
@Day(23)
class Day23(@Text val input: Input<String>) {
private val cups = input.value.toCharArray().map { it.toString().toInt() }
private fun <T> ringSequence(head: Ring.Node<T>) = generateSequence(head) { it.next }
class Ring<T>(items: Iterable<T>) {
class Node<T>(var value: T) {
lateinit var next: Node<T>
override fun toString() = "Node($value -> ${next.value})"
}
private var last: Node<T>? = null
private var first: Node<T>? = null
init {
items.forEach { item ->
val node = Node(item)
if (first == null) first = node
last?.next = node
last = node
}
check(first != null && last != null)
last?.next = first!!
}
fun first() = first!!
}
private fun Ring.Node<Int>.cached(size: Int): Array<Ring.Node<Int>> =
arrayOfNulls<Ring.Node<Int>>(size + 1).also { array ->
array[0] = Ring.Node(-1)
ringSequence(this).take(size).forEach { array[it.value] = it }
} as Array<Ring.Node<Int>>
fun part1(): String {
var currentNode = Ring(cups).first()
val cache = currentNode.cached(cups.size)
val max = cups.maxOrNull()!!
repeat(100) { currentNode = move(max, cache, currentNode) }
return ringSequence(currentNode)
.dropWhile { it.value != 1 }
.drop(1)
.take(cups.size - 1)
.map { it.value }
.joinToString("")
}
fun part2(): Long {
fun fillCups(): List<Int> {
val cups = ArrayList<Int>(1_000_000)
cups.addAll(this.cups)
val highest = this.cups.maxOrNull()!!
for (i in 1..1_000_000 - cups.size) {
cups.add(highest + i)
}
return cups
}
val size = 1_000_000
var currentNode = Ring(fillCups()).first()
val cache = currentNode.cached(size)
repeat(10_000_000) { currentNode = move(max = size, cache, currentNode) }
val one = cache[1]
val a = one.next
val b = a.next
return a.value.toLong() * b.value.toLong()
}
private fun move(max: Int, cache: Array<Ring.Node<Int>>, current: Ring.Node<Int>): Ring.Node<Int> {
val a = current.next
val b = a.next
val c = b.next
current.next = c.next
val aa = a.value
val bb = b.value
val cc = c.value
val destinationNode: Ring.Node<Int>
var i = current.value - 1
while (true) {
if (i < 1) i = max
val value = cache[i].value
if (value == aa || value == bb || value == cc) {
i--
} else {
destinationNode = cache[i]
break
}
}
val destinationNextNode = destinationNode.next
destinationNode.next = a
c.next = destinationNextNode
return current.next
}
}
fun main() = with(createDay<Day23>()) {
println(part1())
println(part2())
}

View File

@ -0,0 +1 @@
871369452