package be.vandewalleh.aoc.days import be.vandewalleh.aoc.utils.input.Day import be.vandewalleh.aoc.utils.input.Lines import org.eclipse.collections.api.bag.Bag import org.eclipse.collections.api.bag.MutableBag import org.eclipse.collections.api.factory.Bags @Day(24) class Day24(@Lines val input: List) { private data class HexPoint(val x: Int, val y: Int, val z: Int) { fun translate(other: HexPoint) = HexPoint(this.x + other.x, this.y + other.y, this.z + other.z) } private enum class Direction(vararg coordinates: Int) { E(1, -1, 0), SE(0, -1, 1), SW(-1, 0, 1), W(-1, 1, 0), NW(0, 1, -1), NE(1, 0, -1); val coordinates = HexPoint(coordinates[0], coordinates[1], coordinates[2]) } private fun parseTile(line: String) = "e|se|sw|w|nw|ne".toRegex() .findAll(line) .flatMap { it.groupValues } .map { Direction.valueOf(it.toUpperCase()) } .toList() private val tiles = input.map { parseTile(it) }.map { it.map { it.coordinates }.reduce { acc, ints -> acc.translate(ints) } } fun part1() = Bags.immutable.ofAll(tiles).selectBlacks().size() private fun Bag.selectBlacks() = selectByOccurrences { it % 2 == 1 } private fun HexPoint.adjacents() = Direction.values().map { this.translate(it.coordinates) } // black -> odd // white -> even || not in bag -> !in black private fun day(bag: MutableBag) { val blacks = bag.selectBlacks().toSet() val all = (bag + bag.flatMap { it.adjacents() }).toSet() for (tile in all) { val adjacents = tile.adjacents() val adjacentBlacks = adjacents.count { it in blacks } val isBlack = tile in blacks if (isBlack && (adjacentBlacks == 0 || adjacentBlacks > 2)) bag.setOccurrences(tile, 2) else if (!isBlack && adjacentBlacks == 2) bag.setOccurrences(tile, 1) } } fun part2(): Int { val bag = Bags.mutable.ofAll(tiles) repeat(100) { day(bag) } return bag.selectBlacks().size() } }