record Monkey(List<Long> items, Worry worry, Test test) {};
record Test(Integer divider, Map<Boolean, Integer> action) {};
record Worry(String arg1, String arg2, BiFunction<Long, Long, Long> op) {};
static BiFunction<Long, Long, Long> mult = (a, b) -> a * b;
static void day11() {
Map<Integer, Map.Entry<Monkey, AtomicLong>> bandarLogs = new TreeMap<>(Map.of(
0, Map.entry(
new Monkey(new CopyOnWriteArrayList<>(List.of(63L, 57L)), new Worry("old", "11", mult), new Test(7, Map.of(true, 6, false, 2))),
new AtomicLong(0)
),
1, Map.entry(
new Monkey(new CopyOnWriteArrayList<>(List.of(82L, 66L, 87L, 78L, 77L, 92L, 83L)), new Worry("old", "1", Long::sum), new Test(11, Map.of(true, 5, false, 0))),
new AtomicLong(0)
),
2, Map.entry(
new Monkey(new CopyOnWriteArrayList<>(List.of(97L, 53L, 53L, 85L, 58L, 54L)), new Worry("old", "7", mult), new Test(13, Map.of(true, 4, false, 3))),
new AtomicLong(0)
),
3, Map.entry(
new Monkey(new CopyOnWriteArrayList<>(List.of(50L)), new Worry("old", "3", Long::sum), new Test(3, Map.of(true, 1, false, 7))),
new AtomicLong(0)
),
4, Map.entry(
new Monkey(new CopyOnWriteArrayList<>(List.of(64L, 69L, 52L, 65L, 73L)), new Worry("old", "6", Long::sum), new Test(17, Map.of(true, 3, false, 7))),
new AtomicLong(0)
),
5, Map.entry(
new Monkey(new CopyOnWriteArrayList<>(List.of(57L, 91L, 65L)), new Worry("old", "5", Long::sum), new Test(2, Map.of(true, 0, false, 6))),
new AtomicLong(0)
),
6, Map.entry(
new Monkey(new CopyOnWriteArrayList<>(List.of(67L, 91L, 84L, 78L, 60L, 69L, 99L, 83L)), new Worry("old", "old", mult), new Test(5, Map.of(true, 2, false, 4))),
new AtomicLong(0)
),
7, Map.entry(
new Monkey(new CopyOnWriteArrayList<>(List.of(58L, 78L, 69L, 65L)), new Worry("old", "7", Long::sum), new Test(19, Map.of(true, 5, false, 1))),
new AtomicLong(0)
)
));
int divider = bandarLogs.values().stream().map(Entry::getKey).mapToInt(m -> m.test().divider()).reduce(1, (a, b) -> a * b);
// int rounds = 20;
int rounds = 10_000;
for (int i = 1; i <= rounds; i++) {
System.out.printf("Round %d\r", i);
bandarLogs.forEach((monkeyN, monkeyEntry) -> {
Monkey monkey = monkeyEntry.getKey();
monkey.items().forEach(item -> {
var a1 = "old".equals(monkey.worry().arg1()) ? item : Integer.parseInt(monkey.worry().arg1());
var a2 = "old".equals(monkey.worry().arg2()) ? item :Integer.parseInt(monkey.worry().arg2());
var newWorryLvl = monkey.worry().op().apply(a1, a2);
newWorryLvl = rounds == 20 ? newWorryLvl / 3 : newWorryLvl % divider;
int recipientMonkey = monkey.test().action().get(
newWorryLvl % monkey.test().divider() == 0
);
bandarLogs.get(recipientMonkey).getKey().items().add(newWorryLvl);
monkey.items().remove(item);
monkeyEntry.getValue().incrementAndGet();
});
});
}
System.out.println();
var result = bandarLogs.values().stream()
.map(Entry::getValue)
.map(AtomicLong::get)
.sorted(Comparator.reverseOrder())
.limit(2)
.reduce((a, b) -> a * b);
System.out.println("Monkey business = " + result);
}