-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
2 changed files
with
157 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
package me.gergo | ||
|
||
import java.io.File | ||
import java.util.* | ||
|
||
private const val Rounds = 10000 | ||
|
||
/** | ||
* Note: this only has Part Two, as I did Part One with a naiive solution that probably takes all the memory in the world, multiplying horribly large | ||
* BigDecimals :) The trick in this one is to remember but delay the computation for as long as possible. As we're only really interested in whether | ||
* the result at the end of a long chain of operations is divisible by N, we can modulo N per every operation - but we must do that for each monkey | ||
* individually, which means we must remember the computation chain (Items.operations in this implementation)! | ||
*/ | ||
fun main() { | ||
val monkeys = File("src/main/resources/input11.txt").readText().split("\n\n") | ||
.map { it.split("\n") } | ||
.map(::parseMonkey) | ||
|
||
|
||
for (i in 1..Rounds) { | ||
for (monkey in monkeys) { | ||
monkey.inspectAndThrowAll(monkeys) | ||
} | ||
} | ||
|
||
for (monkey in monkeys) { | ||
println("Monkey ${monkey.name} inspected items ${monkey.inspections} times") | ||
} | ||
|
||
val result = monkeys.map(Monkey::inspections).sortedDescending().take(2).reduce(Long::times) | ||
println("Level of monkey business: $result") | ||
} | ||
|
||
private class Monkey(val name: Int, val items: Queue<Item>, val operation: Operation, val divisor: Int, val throwToTrue: Int, val throwToFalse: Int) { | ||
var inspections = 0L | ||
|
||
fun inspectAndThrowAll(monkeys: List<Monkey>) { | ||
while (true) { | ||
val item = items.poll() ?: return | ||
item.operations.add(operation) | ||
inspections++ | ||
val throwTo = if (item.divisibleBy(divisor)) throwToTrue else throwToFalse | ||
monkeys[throwTo].catch(item) | ||
} | ||
} | ||
|
||
fun catch(item: Item) { | ||
items.add(item) | ||
} | ||
} | ||
|
||
private data class Item(val value: Int, val operations: MutableList<Operation>) { | ||
fun divisibleBy(divisor: Int): Boolean { | ||
var current = value | ||
for (operation in operations) { | ||
current = when (operation) { | ||
is Mul -> (current * operation.multiplier) % divisor | ||
is Add -> (current + operation.add) % divisor | ||
Square -> (current * current) % divisor | ||
} | ||
} | ||
return current % divisor == 0 | ||
} | ||
} | ||
|
||
private sealed interface Operation | ||
private data class Mul(val multiplier: Int) : Operation | ||
private data class Add(val add: Int) : Operation | ||
private object Square : Operation | ||
|
||
private fun parseMonkey(lines: List<String>): Monkey { | ||
val name = lines[0].replace(Regex("\\D+"), "").toInt() | ||
val items = lines[1].substring(" Starting items: ".length).split(", ").map { Item(it.toInt(), mutableListOf()) } | ||
val operation = parseOperation(lines[2].substring(" Operation: new = ".length)) | ||
val divisor = lines[3].substring(" Test: divisible by ".length).toInt() | ||
val throwToTrue = lines[4].substring(" If true: throw to monkey ".length).toInt() | ||
val throwToFalse = lines[5].substring(" If false: throw to monkey ".length).toInt() | ||
return Monkey( | ||
name, | ||
items.toCollection(LinkedList()), | ||
operation, | ||
divisor, | ||
throwToTrue, | ||
throwToFalse | ||
) | ||
} | ||
|
||
private fun parseOperation(value: String): Operation { | ||
val mr = Regex("(\\w+) ([*+]) (\\w+)").matchEntire(value)!! | ||
assert(mr.groupValues[1] == "old") | ||
val op = mr.groupValues[2] | ||
val opB = mr.groupValues[3] | ||
return if (op == "*") { | ||
if (opB == "old") { | ||
Square | ||
} else { | ||
Mul(opB.toInt()) | ||
} | ||
} else { | ||
Add(opB.toInt()) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
Monkey 0: | ||
Starting items: 89, 84, 88, 78, 70 | ||
Operation: new = old * 5 | ||
Test: divisible by 7 | ||
If true: throw to monkey 6 | ||
If false: throw to monkey 7 | ||
|
||
Monkey 1: | ||
Starting items: 76, 62, 61, 54, 69, 60, 85 | ||
Operation: new = old + 1 | ||
Test: divisible by 17 | ||
If true: throw to monkey 0 | ||
If false: throw to monkey 6 | ||
|
||
Monkey 2: | ||
Starting items: 83, 89, 53 | ||
Operation: new = old + 8 | ||
Test: divisible by 11 | ||
If true: throw to monkey 5 | ||
If false: throw to monkey 3 | ||
|
||
Monkey 3: | ||
Starting items: 95, 94, 85, 57 | ||
Operation: new = old + 4 | ||
Test: divisible by 13 | ||
If true: throw to monkey 0 | ||
If false: throw to monkey 1 | ||
|
||
Monkey 4: | ||
Starting items: 82, 98 | ||
Operation: new = old + 7 | ||
Test: divisible by 19 | ||
If true: throw to monkey 5 | ||
If false: throw to monkey 2 | ||
|
||
Monkey 5: | ||
Starting items: 69 | ||
Operation: new = old + 2 | ||
Test: divisible by 2 | ||
If true: throw to monkey 1 | ||
If false: throw to monkey 3 | ||
|
||
Monkey 6: | ||
Starting items: 82, 70, 58, 87, 59, 99, 92, 65 | ||
Operation: new = old * 11 | ||
Test: divisible by 5 | ||
If true: throw to monkey 7 | ||
If false: throw to monkey 4 | ||
|
||
Monkey 7: | ||
Starting items: 91, 53, 96, 98, 68, 82 | ||
Operation: new = old * old | ||
Test: divisible by 3 | ||
If true: throw to monkey 4 | ||
If false: throw to monkey 2 |