1+ import Day04 .Grid .*
12import cats .data .Store
23import cats .syntax .all .*
34
45object Day04 :
56
67 case class Word (s : String ):
78 val length : Int = s.length
8- val toOptionChars : List [Option [Char ]] = s.toList.map(Some .apply)
9+ val toOptionalChars : List [Option [Char ]] = s.toList.map(_.some)
10+ def reverse : Word = Word (s.reverse)
911
1012 case class Pos (row : Int , col : Int )
1113
@@ -21,28 +23,58 @@ object Day04:
2123
2224 val toVectors : Vector [Vector [Char ]] = rows.map(_.toVector).toVector
2325
24- def toStore : StoreGrid = Store (
26+ val toStore : StoreGrid = Store (
2527 p => toVectors.get(p.row).flatMap(_.get(p.col)),
2628 s = Pos .zero
2729 )
2830
29- def allPositions : List [Pos ] =
31+ val allPositions : List [Pos ] =
3032 rows.zipWithIndex.flatMap((row, rowIndex) => row.zipWithIndex.map((_, colIndex) => Pos (rowIndex, colIndex)))
3133
34+ def allWordChecks (w : Word ): List [WordCheckResult ] =
35+ toStore
36+ .coflatMap(s =>
37+ List (
38+ horizontalPositions,
39+ verticalPositions,
40+ ascDiagonalPositions,
41+ descDiagonalPositions
42+ ).map(wordCheck(_)(w, s))
43+ )
44+ .experiment(_ => allPositions)
45+ .flatten
46+
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+
3254 object Grid :
3355
3456 def parse (rows : List [String ]): Option [Grid ] = Grid (rows = rows.map(_.toList)).some
3557
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+
3661 /*
3762 XMAS
3863 ....
3964 ....
4065 ....
4166 */
42- def topLeftPositions (w : Word )(from : Pos ): List [Pos ] =
67+ def horizontalPositions (w : Word )(from : Pos ): List [Pos ] =
4368 List .range(start = from.col, end = from.col + w.length).map(col => Pos (from.row, col))
4469
45- def wordCheckTopLeft (w : Word , store : StoreGrid ): WordCheckResult = wordCheck(topLeftPositions, w, store)
70+ /*
71+ X...
72+ M...
73+ A...
74+ S...
75+ */
76+ def verticalPositions (w : Word )(from : Pos ): List [Pos ] =
77+ List .range(start = from.row, end = from.row + w.length).map(row => Pos (row, from.col))
4678
4779 /*
4880 ...S
@@ -53,8 +85,6 @@ object Day04:
5385 def ascDiagonalPositions (w : Word )(from : Pos ): List [Pos ] =
5486 List .range(start = 0 , end = w.length).reverse.map(i => Pos (row = i + from.row, col = w.length - i - 1 + from.col))
5587
56- def wordCheckAscDiagonal (w : Word , store : StoreGrid ): WordCheckResult = wordCheck(ascDiagonalPositions, w, store)
57-
5888 /*
5989 X...
6090 .M..
@@ -63,8 +93,3 @@ object Day04:
6393 */
6494 def descDiagonalPositions (w : Word )(from : Pos ): List [Pos ] =
6595 List .range(start = 0 , end = w.length).map(i => Pos (row = i + from.row, col = i + from.col))
66-
67- def wordCheckDescDiagonal (w : Word , store : StoreGrid ): WordCheckResult = wordCheck(descDiagonalPositions, w, store)
68-
69- def wordCheck (positions : Word => Pos => List [Pos ], w : Word , store : StoreGrid ): WordCheckResult =
70- if w.toOptionChars == store.experiment(positions(w)) then WordCheckResult .Found else WordCheckResult .NotFound
0 commit comments