Created
January 8, 2022 05:19
-
-
Save sungkmi/c532b0725b1a47677364a285527c7b47 to your computer and use it in GitHub Desktop.
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
package lascala.aoc2021.day1_10.day4 | |
case class Bingo( | |
board: BingoBoard, | |
marked: Marked, | |
) | |
extension (b: Bingo) | |
def checkBingo(n: Int): Option[Bingo] = b.board.indexOf(n) match | |
case None => Some(b) | |
case Some((r, c)) => | |
def checkRow: Boolean = (0 until 5).forall { i => | |
i == c || b.marked.isSet(r, i) | |
} | |
def checkColumn: Boolean = (0 until 5).forall { i => | |
i == r || b.marked.isSet(i, c) | |
} | |
if checkRow || checkColumn then None | |
else Some(b.copy(marked = b.marked.set(r, c))) | |
end checkBingo | |
def sum: Int = | |
val unmarked = for | |
(number, (r, c)) <- b.board.toMap | |
if !b.marked.isSet(r, c) | |
yield number | |
unmarked.sum | |
end sum | |
opaque type BingoBoard = Map[Int, (Int, Int)] | |
extension (bb: BingoBoard) | |
def toMap: Map[Int, (Int, Int)] = bb | |
def indexOf(n: Int): Option[(Int, Int)] = bb.get(n) | |
end extension | |
object BingoBoard: | |
def parse(s: String): BingoBoard = | |
def parseLine(line: String): Seq[Int] = | |
line.sliding(3, 3).map(_.trim.toInt).toSeq | |
val rc = for | |
(line, rowIndex) <- s.split("\n").zipWithIndex | |
(digit, colIndex) <- parseLine(line).zipWithIndex | |
yield (digit, (rowIndex, colIndex)) | |
rc.toMap | |
end parse | |
end BingoBoard | |
opaque type Row = BigInt | |
extension (r: Row) | |
def isSet(n: Int): Boolean = r.testBit(n) | |
def set(n: Int): Row = r.setBit(n) | |
object Row: | |
def empty: Row = BigInt(0) | |
opaque type Marked = IndexedSeq[Row] | |
extension (m: Marked) | |
def isSet(r: Int, c: Int): Boolean = m(r).isSet(c) | |
def set(r: Int, c: Int): Marked = m.updated(r, m(r).set(c)) | |
object Marked: | |
def empty: Marked = IndexedSeq.fill(5)(Row.empty) | |
def parse(s: String): (Seq[Int], Seq[Bingo]) = | |
val inputs = s.split("\n\n") | |
val numbers = inputs.head.split(",").map(_.toInt) | |
val bingos = inputs.tail.map(BingoBoard.parse).map(Bingo(_, Marked.empty)) | |
(numbers, bingos) | |
def solve1(s: String): BigInt = | |
val (numbers, bingos) = parse(s) | |
@annotation.tailrec | |
def loop(numbers: Seq[Int], bingos: Seq[Bingo], acc: Int): BigInt = | |
val number = numbers.head | |
val nextBingos = bingos.map(_.checkBingo(number)) | |
if nextBingos.forall(_.nonEmpty) then | |
loop(numbers.tail, nextBingos.flatten, acc + number) | |
else | |
val Some(i) = nextBingos.zipWithIndex.find(_._1.isEmpty).map(_._2) | |
(bingos(i).sum - number) * number | |
end loop | |
loop(numbers, bingos, 0) | |
end solve1 | |
def solve2(s: String): BigInt = | |
val (numbers, bingos) = parse(s) | |
@annotation.tailrec | |
def loop(numbers: Seq[Int], bingos: Seq[Bingo], acc: Int): BigInt = | |
val number = numbers.head | |
val nextBingos = bingos.map(_.checkBingo(number)) | |
if nextBingos.forall(_.isEmpty) then (bingos.head.sum - number) * number | |
else loop(numbers.tail, nextBingos.flatten, acc + number) | |
end loop | |
loop(numbers, bingos, 0) | |
end solve2 | |
@main def part1: Unit = | |
val ans = solve1(input) | |
println(ans) | |
@main def part2: Unit = | |
val ans = solve2(input) | |
println(ans) | |
//val input = |
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
package lascala.aoc2021.day1_10.day4 | |
import minitest.SimpleTestSuite | |
import hedgehog.minitest.HedgehogSupport | |
import hedgehog.* | |
object Day4Test extends SimpleTestSuite with HedgehogSupport: | |
val testInput = """7,4,9,5,11,17,23,2,0,14,21,24,10,16,13,6,15,25,12,22,18,20,8,19,3,26,1 | |
22 13 17 11 0 | |
8 2 23 4 24 | |
21 9 14 16 7 | |
6 10 3 18 5 | |
1 12 20 15 19 | |
3 15 0 2 22 | |
9 18 13 17 5 | |
19 8 7 25 23 | |
20 11 10 24 4 | |
14 21 16 12 6 | |
14 21 17 24 4 | |
10 16 15 9 19 | |
18 8 23 26 20 | |
22 11 13 6 5 | |
2 0 12 3 7""" | |
example("day4 - bingo board") { | |
val boardString = """22 13 17 11 0 | |
8 2 23 4 24 | |
21 9 14 16 7 | |
6 10 3 18 5 | |
1 12 20 15 19""" | |
val board = BingoBoard.parse(boardString) | |
Result.all( | |
List( | |
board.indexOf(0) ==== Some((0, 4)), | |
board.indexOf(1) ==== Some((4, 0)), | |
board.indexOf(2) ==== Some((1, 1)), | |
), | |
) | |
} | |
example("day4 - solve1") { | |
solve1(testInput) ==== 4512 | |
} | |
example("day4 - solve2") { | |
solve2(testInput) ==== 1924 | |
} | |
end Day4Test |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment