@@ -15,7 +15,15 @@ object Day12 {
1515
1616 case class Input (shapes : Seq [Shape ], regions : Seq [Region ])
1717
18- /* def fits(shapes: Seq[Shape])(region: Region): Boolean = {
18+ trait Solution {
19+ def fits (shapes : Seq [Shape ])(region : Region ): Boolean
20+
21+ def countFits (input : Input ): Int =
22+ input.regions.count(fits(input.shapes))
23+ }
24+
25+ object NaiveSolution extends Solution {
26+ /* def fits(shapes: Seq[Shape])(region: Region): Boolean = {
1927
2028 def helper(grid: Grid[Boolean], shapeCounts: Seq[Int]): Boolean = {
2129 val shapeI = shapeCounts.indexWhere(_ > 0)
@@ -40,35 +48,33 @@ object Day12 {
4048 helper(initialGrid, region.shapeCounts)
4149 }*/
4250
51+ // probably broken: skips over poss when finding place for a shape
52+ override def fits (shapes : Seq [Shape ])(region : Region ): Boolean = {
53+ val shapeOrientationBox = Box (Pos .zero, region.size - Pos (3 , 3 )) // assuming all shappes of same size
4354
44- /* // probably broken: skips over poss when finding place for a shape
45- def fits(shapes: Seq[Shape])(region: Region): Boolean = {
46- val shapeOrientationBox = Box(Pos.zero, region.size - Pos(3, 3)) // assuming all shappes of same size
47-
48- def helper(grid: Grid[Boolean], shapeCounts: Seq[Int], poss: List[Pos]): Boolean = {
49- val shapeI = shapeCounts.indexWhere(_ > 0)
50- if (shapeI < 0)
51- true // nothing more to fit
52- else {
53- val newShapeCounts = shapeCounts.updated(shapeI, shapeCounts(shapeI) - 1)
54- val shape = shapes(shapeI)
55- (for {
56- shapeOrientation <- shape.orientations.iterator
57- shapeOrientationSize = Pos(shapeOrientation(0).size, shapeOrientation.size)
58- shapeOrientationBox2 = Box(Pos.zero, shapeOrientationSize - Pos(1, 1))
59- case pos :: newPoss <- poss.tails
60- if shapeOrientationBox2.iterator.forall(p => !(shapeOrientation(p) && grid(pos + p)))
61- newGrid = shapeOrientationBox2.iterator.foldLeft(grid)((newGrid, p) => newGrid.updatedGrid(pos + p, shapeOrientation(p)))
62- } yield helper(newGrid, newShapeCounts, newPoss)).exists(identity)
55+ def helper (grid : Grid [Boolean ], shapeCounts : Seq [Int ], poss : List [Pos ]): Boolean = {
56+ val shapeI = shapeCounts.indexWhere(_ > 0 )
57+ if (shapeI < 0 )
58+ true // nothing more to fit
59+ else {
60+ val newShapeCounts = shapeCounts.updated(shapeI, shapeCounts(shapeI) - 1 )
61+ val shape = shapes(shapeI)
62+ (for {
63+ shapeOrientation <- shape.orientations.iterator
64+ shapeOrientationSize = Pos (shapeOrientation(0 ).size, shapeOrientation.size)
65+ shapeOrientationBox2 = Box (Pos .zero, shapeOrientationSize - Pos (1 , 1 ))
66+ case pos :: newPoss <- poss.tails
67+ if shapeOrientationBox2.iterator.forall(p => ! (shapeOrientation(p) && grid(pos + p)))
68+ newGrid = shapeOrientationBox2.iterator.foldLeft(grid)((newGrid, p) => newGrid.updatedGrid(pos + p, shapeOrientation(p)))
69+ } yield helper(newGrid, newShapeCounts, newPoss)).exists(identity)
70+ }
6371 }
64- }
65-
66- val initialGrid = Vector.fill(region.size.y, region.size.x)(false)
67- helper(initialGrid, region.shapeCounts, shapeOrientationBox.iterator.toList)
68- }*/
6972
73+ val initialGrid = Vector .fill(region.size.y, region.size.x)(false )
74+ helper(initialGrid, region.shapeCounts, shapeOrientationBox.iterator.toList)
75+ }
7076
71- /* def fits(shapes: Seq[Shape])(region: Region): Boolean = {
77+ /* def fits(shapes: Seq[Shape])(region: Region): Boolean = {
7278 val shapeOrientationBox = Box(Pos.zero, region.size - Pos(3, 3)) // assuming all shappes of same size
7379
7480 def helper(grid: Grid[Boolean], shapeCounts: Seq[Int], poss: List[Pos]): Boolean = {
@@ -100,18 +106,31 @@ object Day12 {
100106 val initialGrid = Vector.fill(region.size.y, region.size.x)(false)
101107 helper(initialGrid, region.shapeCounts, shapeOrientationBox.iterator.toList)
102108 }*/
103-
104- // cheat solution
105- def fits (shapes : Seq [Shape ])(region : Region ): Boolean = {
106- shapes
107- .map(_.countGrid(identity))
108- .lazyZip(region.shapeCounts)
109- .map(_ * _)
110- .sum <= Box (Pos .zero, region.size - Pos (1 , 1 )).size[Int ]
111109 }
112110
113- def countFits (input : Input ): Int =
114- input.regions.count(fits(input.shapes))
111+ object SanitySolution extends Solution {
112+ override def fits (shapes : Seq [Shape ])(region : Region ): Boolean = {
113+ val area = Box (Pos (1 , 1 ), region.size).size[Int ]
114+ val areaLowerBound = // only counting the #-s in shapes
115+ shapes
116+ .map(_.countGrid(identity))
117+ .lazyZip(region.shapeCounts)
118+ .map(_ * _)
119+ .sum
120+ val areaUpperBound = // counting area needed if no "overlaps" are possible
121+ shapes
122+ .map(_.sizeGrid)
123+ .lazyZip(region.shapeCounts)
124+ .map(_ * _)
125+ .sum
126+ if (areaUpperBound <= area)
127+ true
128+ else if (areaLowerBound > area)
129+ false
130+ else
131+ throw IllegalArgumentException (" undecidable by sanity check" )
132+ }
133+ }
115134
116135 def parseShape (s : String ): Shape = s.linesIterator.tail.map(_.map(_ == '#' ).toVector).toVector
117136
@@ -128,6 +147,6 @@ object Day12 {
128147 lazy val input : String = scala.io.Source .fromInputStream(getClass.getResourceAsStream(" day12.txt" )).mkString.trim
129148
130149 def main (args : Array [String ]): Unit = {
131- println(countFits(parseInput(input)))
150+ println(SanitySolution . countFits(parseInput(input)))
132151 }
133152}
0 commit comments