-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathTask03_02.scala
53 lines (46 loc) · 2.12 KB
/
Task03_02.scala
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
import cats.syntax.option._
import ZioImplicits.ZioOps
import zio._
object Task03_02 extends ZIOAppDefault with ReadFileSuite {
override def run: ZIO[Any with ZIOAppArgs with Scope, Any, Any] = for {
lines <- getLines("03_input.txt")
numbers <- parseNumbers(lines)
points <- parsePoints(lines)
result <- getResult(numbers, points)
_ <- Console.printLine(result)
} yield ExitCode.success
private def parseNumbers(lines: Seq[String]): UIO[Seq[NumberWithPosition]] =
lines.zipWithIndex.foldLeft(Seq.empty[NumberWithPosition]) {
case (acc, (line, yIndex)) => acc ++ parseNumbersFromLine(line, yIndex)
}.succeed
private def parseNumbersFromLine(line: String, yIndex: Int = 0): Seq[NumberWithPosition] = {
val (acc, cacheNumber) = line.zipWithIndex.foldLeft((Seq.empty[NumberWithPosition], none[NumberWithPosition])) {
case ((acc, None), (number, xIndex)) if number.isDigit =>
(acc, NumberWithPosition(number.asDigit, (xIndex - 1, yIndex - 1), (xIndex + 1, yIndex + 1)).some)
case ((acc, Some(cacheNumber)), (number, xIndex)) if number.isDigit =>
(acc, cacheNumber.addDigitWithIndex(number.asDigit, (xIndex, yIndex)).some)
case ((acc, Some(cacheNumber)), (_, _)) => (cacheNumber +: acc, none[NumberWithPosition])
case ((acc, None), (_, _)) => (acc, none[NumberWithPosition])
}
cacheNumber match {
case Some(value) => value +: acc
case None => acc
}
}
private def parsePoints(lines: Seq[String]): UIO[Seq[(Int, Int)]] =
lines.zipWithIndex.foldLeft(Seq.empty[(Int, Int)]) {
case (acc, (line, yIndex)) => acc ++ parsePointsFromLine(line, yIndex)
}.succeed
private def parsePointsFromLine(line: String, yIndex: Int = 0): Seq[(Int, Int)] =
line.zipWithIndex.foldLeft(Seq.empty[(Int, Int)]) {
case (acc, ('*', xIndex)) => (xIndex, yIndex) +: acc
case (acc, _) => acc
}
private def getResult(numbers: Seq[NumberWithPosition], points: Seq[(Int, Int)]): UIO[Long] =
points.view
.map(point => numbers.filter(_.isNearBy(point)))
.filter(_.length == 2)
.map(_.map(_.number).product)
.sum
.succeed
}