package aoc2023 import println import readInput import splitInts /* --- Day 4: Scratchcards --- https://adventofcode.com/2023/day/4 */ fun main() { val inlineTestInput = """ Card 1: 41 48 83 86 17 | 83 86 6 31 17 9 48 53 Card 2: 13 32 20 16 61 | 61 30 68 82 17 32 24 19 Card 3: 1 21 53 59 44 | 69 82 63 72 16 21 14 1 Card 4: 41 92 73 84 69 | 59 84 76 51 58 5 54 83 Card 5: 87 83 26 28 32 | 88 30 70 12 93 22 82 36 Card 6: 31 18 13 56 72 | 74 77 10 23 35 67 36 11 """ fun part1(input: List): Int { return input.map { "Card +(\\d+): (.*)".toRegex().matchEntire(it)?.destructured ?.let { (id, game) -> val (wins, numbers) = game.split(" | ") val winSet = wins.splitInts().toSet() val numberSet = numbers.splitInts().toSet() val matches = winSet.intersect(numberSet) 1 shl (matches.size - 1) } }.sumOf { it!! } } fun part2(input: List): Int { val winTable = input.map { "Card +(\\d+): (.*)".toRegex().matchEntire(it)?.destructured ?.let { (id, game) -> val (wins, numbers) = game.split(" | ") val winSet = wins.splitInts().toSet() val numberSet = numbers.splitInts().toSet() val matches = winSet.intersect(numberSet) matches.size }!! }.toList() val accTable = IntArray(winTable.size) for (i in winTable.indices.reversed()) { var sum = 1 for (j in i + 1 until (i + winTable[i] + 1).coerceAtMost(winTable.size)) { sum += accTable[j] } accTable[i] = sum } return accTable.sum() } // test if implementation meets criteria from the description, like: val testInput = inlineTestInput.trim().reader().readLines() //val testInput = readInput("aoc2023/Day04_test") val testInputPart1Result = part1(testInput) println("Part 1 Test: $testInputPart1Result") val testInputPart2Result = part2(testInput) println("Part 2 Test: $testInputPart2Result") check(testInputPart1Result == 13) check(testInputPart2Result == 30) val input = readInput("aoc2023/Day04") part1(input).println() part2(input).println() }