@@ -19,77 +19,92 @@ object Day04:
1919 enum WordCheckResult :
2020 case Found , NotFound
2121
22+ def toInt : Int = this match {
23+ case Found => 1
24+ case NotFound => 0
25+ }
26+ def toBoolean : Boolean = this match {
27+ case Found => true
28+ case NotFound => false
29+ }
30+
31+ object WordCheckResult :
32+ def from (b : Boolean ): WordCheckResult = if b then Found else NotFound
33+
2234 case class Grid (rows : List [List [Char ]]):
2335
2436 val toVectors : Vector [Vector [Char ]] = rows.map(_.toVector).toVector
2537
26- val toStore : StoreGrid = Store (
27- p => toVectors.get(p.row).flatMap(_.get(p.col)),
28- s = Pos .zero
29- )
38+ val toStore : StoreGrid = Store (p => toVectors.get(p.row).flatMap(_.get(p.col)), s = Pos .zero)
3039
3140 val allPositions : List [Pos ] =
3241 rows.zipWithIndex.flatMap((row, rowIndex) => row.zipWithIndex.map((_, colIndex) => Pos (rowIndex, colIndex)))
3342
43+ def allOccurrences (s : String ): Int =
44+ val w = Word (s)
45+ (allWordChecks(w) ++ allWordChecks(w.reverse)).foldMap(_.toInt)
46+
3447 def allWordChecks (w : Word ): List [WordCheckResult ] =
3548 toStore
36- .coflatMap(s =>
37- List (
38- horizontalPositions,
39- verticalPositions,
40- ascDiagonalPositions,
41- descDiagonalPositions
42- ).map(wordCheck(_)(w, s))
43- )
49+ .coflatMap(wordChecks(w, _))
4450 .experiment(_ => allPositions)
4551 .flatten
4652
47- def allOccurrences ( s : String ) : Int =
48- val w = Word (s)
49- (allWordChecks(w) ++ allWordChecks(w.reverse)).foldMap {
50- case WordCheckResult . Found => 1
51- case WordCheckResult . NotFound => 0
52- }
53+ // part 2
54+ def allCrossOccurrences ( s : String ) : Int =
55+ toStore
56+ .coflatMap(crossWordCheck( Word (s), _))
57+ .experiment(_ => allPositions)
58+ .foldMap(_.toInt)
5359
5460 object Grid :
5561
5662 def parse (rows : List [String ]): Option [Grid ] = Grid (rows = rows.map(_.toList)).some
5763
58- def wordCheck (positions : Word => Pos => List [Pos ])(w : Word , store : StoreGrid ): WordCheckResult =
59- if w.toOptionalChars == store.experiment(positions(w)) then WordCheckResult .Found else WordCheckResult .NotFound
60-
61- /*
62- XMAS
63- ....
64- ....
65- ....
66- */
64+ def wordChecks (w : Word , store : StoreGrid ): List [WordCheckResult ] =
65+ List (
66+ horizontalPositions,
67+ verticalPositions,
68+ ascDiagonalPositions,
69+ descDiagonalPositions
70+ ).map(wordCheck(_, w, store))
71+
72+ def wordCheck (positions : Word => Pos => List [Pos ], w : Word , store : StoreGrid ): WordCheckResult =
73+ WordCheckResult .from(w.toOptionalChars == store.experiment(positions(w)))
74+
75+ /* XMAS
76+ ....
77+ ....
78+ .... */
6779 def horizontalPositions (w : Word )(from : Pos ): List [Pos ] =
6880 List .range(start = from.col, end = from.col + w.length).map(col => Pos (from.row, col))
6981
70- /*
71- X...
72- M...
73- A...
74- S...
75- */
82+ /* X...
83+ M...
84+ A...
85+ S... */
7686 def verticalPositions (w : Word )(from : Pos ): List [Pos ] =
7787 List .range(start = from.row, end = from.row + w.length).map(row => Pos (row, from.col))
7888
79- /*
80- ...S
81- ..A.
82- .M..
83- X...
84- */
89+ /* ...S
90+ ..A.
91+ .M..
92+ X... */
8593 def ascDiagonalPositions (w : Word )(from : Pos ): List [Pos ] =
8694 List .range(start = 0 , end = w.length).reverse.map(i => Pos (row = i + from.row, col = w.length - i - 1 + from.col))
8795
88- /*
89- X...
90- .M..
91- ..A.
92- ...S
93- */
96+ /* X...
97+ .M..
98+ ..A.
99+ ...S */
94100 def descDiagonalPositions (w : Word )(from : Pos ): List [Pos ] =
95101 List .range(start = 0 , end = w.length).map(i => Pos (row = i + from.row, col = i + from.col))
102+
103+ // part 2
104+ def crossWordCheck (w : Word , store : StoreGrid ): WordCheckResult =
105+ def ascDiagonalCheck : Word => Boolean = wordCheck(ascDiagonalPositions, _, store).toBoolean
106+ def descDiagonalCheck : Word => Boolean = wordCheck(descDiagonalPositions, _, store).toBoolean
107+ WordCheckResult .from(
108+ (ascDiagonalCheck(w) || ascDiagonalCheck(w.reverse)) &&
109+ (descDiagonalCheck(w) || descDiagonalCheck(w.reverse))
110+ )
0 commit comments