-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathDay07.kt
70 lines (57 loc) · 2.36 KB
/
Day07.kt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
/*
* Copyright (c) 2019 by Todd Ginsberg
*/
/**
* Advent of Code 2019, Day 7 - Amplification Circuit
* Problem Description: http://adventofcode.com/2019/day/7
* Blog Post/Commentary: https://todd.ginsberg.com/post/advent-of-code/2019/day7/
*/
package com.ginsberg.advent2019
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
class Day07(input: String) {
private val program: IntArray = input.split(",").map { it.toInt() }.toIntArray()
fun solvePart1(): Int =
listOf(0, 1, 2, 3, 4).permutations().map { runPhase(it) }.max()
?: throw IllegalStateException("No max value, something is wrong")
fun solvePart2(): Int = runBlocking {
listOf(5, 6, 7, 8, 9).permutations().map { runAmplified(it) }.max()
?: throw IllegalStateException("No max value, something is wrong")
}
private fun runPhase(settings: List<Int>): Int =
(0..4).fold(0) { past, id ->
IntCodeComputer(program.copyOf(), mutableListOf(settings[id], past)).run().first()
}
private suspend fun runAmplified(settings: List<Int>): Int = coroutineScope {
val a = IntCodeComputer(program.copyOf(), listOf(settings[0], 0).toChannel())
val b = IntCodeComputer(program.copyOf(), a.output.andSend(settings[1]))
val c = IntCodeComputer(program.copyOf(), b.output.andSend(settings[2]))
val d = IntCodeComputer(program.copyOf(), c.output.andSend(settings[3]))
val e = IntCodeComputer(program.copyOf(), d.output.andSend(settings[4]))
val channelSpy = ChannelSpy(e.output, a.input)
coroutineScope {
launch { channelSpy.listen() }
launch { a.runSuspending() }
launch { b.runSuspending() }
launch { c.runSuspending() }
launch { d.runSuspending() }
launch { e.runSuspending() }
}
channelSpy.spy.receive()
}
private suspend fun <T> Channel<T>.andSend(msg: T): Channel<T> =
this.also { send(msg) }
}
class ChannelSpy<T>(
private val input: Channel<T>,
private val output: Channel<T>,
val spy: Channel<T> = Channel(Channel.CONFLATED)) {
suspend fun listen() = coroutineScope {
for (received in input) {
spy.send(received)
output.send(received)
}
}
}