Skip to content

Commit 9a88633

Browse files
committed
feat(aoc-2023): day4 part 1 and 2
1 parent 85ca90e commit 9a88633

14 files changed

Lines changed: 341 additions & 8 deletions

File tree

2023/src/main/scala/day04.scala

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
package com.markkovari.adventofcode.day04
2+
3+
import scala.util.matching.Regex.Match
4+
5+
case class Card(id: Int, numbers: List[Int], winningNumbers: List[Int]) {
6+
private def matches(): Set[Int] = {
7+
numbers.toSet.intersect(winningNumbers.toSet)
8+
}
9+
10+
def getScore(): Int = {
11+
math.pow(2, matches().size - 1).intValue
12+
}
13+
}
14+
15+
def parseCard(input: String): Card =
16+
input match {
17+
case s"Card ${id}: ${numbers} | ${winningNumbers}" =>
18+
Card(
19+
id.trim().toInt,
20+
// Sould be able to do this with a regex, but I can't figure it out right now :| by "whitespaces""
21+
numbers.split(" ").filter(!_.isEmpty).map(_.toInt).toList,
22+
winningNumbers.split(" ").filter(!_.isEmpty).map(_.toInt).toList
23+
)
24+
}
25+
26+
def parseCards(input: String): List[Card] =
27+
input.split("\n").map(parseCard).toList
28+
29+
def part2(input: String): BigInt =
30+
parseCards(input)
31+
.map(_.getScore())
32+
.foldLeft((0, Vector(1))) { case ((numCards, multiplicities), winning) =>
33+
val thisMult = multiplicities(0)
34+
val restMult = multiplicities
35+
.drop(1)
36+
.padTo(Math.max(1, winning), 1)
37+
.zipWithIndex
38+
.map((mult, idx) => if idx < winning then mult + thisMult else mult)
39+
(numCards + thisMult, restMult)
40+
}
41+
._1
42+
43+
def countWinning(card: String): Int =
44+
val numbers = card
45+
.substring(card.indexOf(":") + 1) // discard "Card X:"
46+
.split(" ")
47+
.filterNot(_.isEmpty())
48+
val (winningNumberStrs, givenNumberStrs) = numbers.span(_ != "|")
49+
val winningNumbers = winningNumberStrs.map(_.toInt).toSet
50+
// drop the initial "|"
51+
val givenNumbers = givenNumberStrs.drop(1).map(_.toInt).toSet
52+
winningNumbers.intersect(givenNumbers).size
53+
end countWinning
54+
55+
def winningCounts(input: String): Iterator[Int] =
56+
input.linesIterator.map(countWinning)
57+
end winningCounts
58+
59+
def part1_(input: String): String =
60+
winningCounts(input)
61+
.map(winning => if winning > 0 then Math.pow(2, winning - 1).toInt else 0)
62+
.sum
63+
.toString()
64+
end part1_
65+
66+
def part2_(input: String): String =
67+
winningCounts(input)
68+
// we only track the multiplicities of the next few cards as needed, not all of them;
69+
// and the first element always exists, and corresponds to the current card;
70+
// and the elements are always positive (because there is at least 1 original copy of each card)
71+
.foldLeft((0, Vector(1))) { case ((numCards, multiplicities), winning) =>
72+
val thisMult = multiplicities(0)
73+
val restMult = multiplicities
74+
.drop(1)
75+
// these are the original copies of the next few cards
76+
.padTo(Math.max(1, winning), 1)
77+
.zipWithIndex
78+
// these are the extra copies we just won
79+
.map((mult, idx) => if idx < winning then mult + thisMult else mult)
80+
(numCards + thisMult, restMult)
81+
}
82+
._1
83+
.toString()
84+
end part2_
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
Card 1: 41 48 83 86 17 | 83 86 6 31 17 9 48 53
2+
Card 2: 13 32 20 16 61 | 61 30 68 82 17 32 24 19
3+
Card 3: 1 21 53 59 44 | 69 82 63 72 16 21 14 1
4+
Card 4: 41 92 73 84 69 | 59 84 76 51 58 5 54 83
5+
Card 5: 87 83 26 28 32 | 88 30 70 12 93 22 82 36
6+
Card 6: 31 18 13 56 72 | 74 77 10 23 35 67 36 11

2023/src/test/resources/4/values

Lines changed: 197 additions & 0 deletions
Large diffs are not rendered by default.

0 commit comments

Comments
 (0)