From cf500a26c083bedb730a52be69535d438542f587 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 14 Dec 2023 09:27:24 +0200 Subject: [PATCH] Clean up 2023 day 14 --- .../eu/sim642/adventofcode2023/Day14.scala | 129 +++++------------- .../sim642/adventofcode2023/Day14Test.scala | 8 +- 2 files changed, 35 insertions(+), 102 deletions(-) diff --git a/src/main/scala/eu/sim642/adventofcode2023/Day14.scala b/src/main/scala/eu/sim642/adventofcode2023/Day14.scala index 133194be..93cee089 100644 --- a/src/main/scala/eu/sim642/adventofcode2023/Day14.scala +++ b/src/main/scala/eu/sim642/adventofcode2023/Day14.scala @@ -5,112 +5,45 @@ import eu.sim642.adventofcodelib.cycle.{NaiveCycleFinder, NaiverCycleFinder} object Day14 { - def rollColumn(column: Vector[Char]): Vector[Char] = { + def rollLeft(row: Vector[Char]): Vector[Char] = { - /*def rollOne(column: Vector[Char]): Vector[Char] = { - ('#' +: column :+ '.') - .sliding(3) - .map({ - case Seq(_ , '#', _ ) => '#' - - case Seq(_, '.', '#') => '.' - case Seq('#', 'O', _) => 'O' - case Seq(_, '.', 'O') => 'O' - - case Seq('.', 'O', 'O') => 'O' - case Seq('O', 'O', 'O') => 'O' - - case Seq(_, '.', '.') => '.' - - case Seq('O', 'O', '.') => 'O' - case Seq('.', 'O', '.') => '.' - case Seq('.', 'O', '#') => '.' - //case Seq('#', 'O', 'O') => 'O' - //case Seq('O', 'O', '.') => 'O' - //case Seq('O', '.', 'O') => 'O' - //case Seq('.', 'O', '.') => '.' - //case Seq('O', '.', '.') => '.' - //case Seq('.', '.', '#') => '.' - //case Seq('.', '#', '#') => '#' - //case Seq('#', '#', '.') => '#' - //case Seq('O', 'O', 'O') => 'O' - //case Seq('.', '.', '.') => '.' - //case Seq('#', '.', '.') => '.' - //case Seq('.', '.', 'O') => 'O' - //case Seq('.', 'O', 'O') => 'O' - //case Seq('#', '.', 'O') => 'O' - //case Seq('.', '#', 'O') => '#' - //case Seq('#', 'O', '.') => 'O' - //case Seq('O', '.', '#') => '.' - //case Seq('.', '#', '.') => '#' - //case Seq('#', '.', '#') => '.' - //case Seq('.', 'O', '#') => '.' - //case Seq('O', '#', '.') => '#' - case x => throw new IllegalArgumentException(x.toString()) - }) - .toVector - }*/ - - def rollOne(column: Vector[Char]): Vector[Char] = { - - def helper(column: List[Char]): List[Char] = column match { - case Nil => Nil - case '#' :: Nil => '#' :: Nil - case '.' :: Nil => '.' :: Nil - case 'O' :: Nil => 'O' :: Nil - case 'O' :: 'O' :: newColumn => 'O' :: helper('O' :: newColumn) - case 'O' :: '.' :: newColumn => 'O' :: helper('.' :: newColumn) - case '.' :: 'O' :: newColumn => 'O' :: helper('.' :: newColumn) - case '.' :: '.' :: newColumn => '.' :: helper('.' :: newColumn) - case '.' :: '#' :: newColumn => '.' :: helper('#' :: newColumn) - case '#' :: '#' :: newColumn => '#' :: helper('#' :: newColumn) - case '#' :: 'O' :: newColumn => '#' :: helper('O' :: newColumn) - case '#' :: '.' :: newColumn => '#' :: helper('.' :: newColumn) - case 'O' :: '#' :: newColumn => 'O' :: helper('#' :: newColumn) - case _ => throw new IllegalArgumentException(column.toString()) - } - - helper(column.toList).toVector + def rollOne(row: List[Char]): List[Char] = row match { + case Nil => Nil + case _ :: Nil => row + case '.' :: 'O' :: newColumn => 'O' :: rollOne('.' :: newColumn) + case prev :: newColumn => prev :: rollOne(newColumn) } - NaiveCycleFinder.find(column, rollOne).cycleHead - } - - def totalLoad(grid: Grid[Char]): Int = { - grid.transpose - .map(rollColumn) - .tapEach(println) - .map(_.reverse.zipWithIndex.map({ - case ('O', i) => i + 1 - case _ => 0 - }).sum) - .sum + NaiveCycleFinder.find(row.toList, rollOne).cycleHead.toVector // TODO: simpler fixpoint finding? } - def rollNorth(grid: Grid[Char]): Grid[Char] = grid.transpose.map(rollColumn).transpose - def rollWest(grid: Grid[Char]): Grid[Char] = grid.map(rollColumn) + def rollNorth(grid: Grid[Char]): Grid[Char] = grid.transpose.map(rollLeft).transpose + def rollWest(grid: Grid[Char]): Grid[Char] = grid.map(rollLeft) def rollSouth(grid: Grid[Char]): Grid[Char] = rollNorth(grid.reverse).reverse def rollEast(grid: Grid[Char]): Grid[Char] = rollWest(grid.map(_.reverse)).map(_.reverse) + def rollCycle(grid: Grid[Char]): Grid[Char] = rollEast(rollSouth(rollWest(rollNorth(grid)))) + + trait Part { + def roll(grid: Grid[Char]): Grid[Char] + + def totalNorthLoad(grid: Grid[Char]): Int = { + roll(grid) + .transpose + .map(_.reverse.zipWithIndex.map({ + case ('O', i) => i + 1 + case _ => 0 + }).sum) + .sum + } + } - def rollCycle(grid: Grid[Char]): Grid[Char] = - rollEast(rollSouth(rollWest(rollNorth(grid)))) - - def rollCycles(grid: Grid[Char], cycles: Long = 1000000000L): Grid[Char] = { - val cycle = NaiverCycleFinder.find(grid, rollCycle) - // TODO: Long cycle indexing - //cycle(cycles) - val shortI = (cycles - cycle.stemLength) % cycle.cycleLength - cycle(cycle.stemLength + shortI.toInt) + object Part1 extends Part { + override def roll(grid: Grid[Char]): Grid[Char] = rollNorth(grid) } - def totalLoad2(grid: Grid[Char], cycles: Long = 1000000000L): Int = { - rollCycles(grid, cycles) - .transpose - .map(_.reverse.zipWithIndex.map({ - case ('O', i) => i + 1 - case _ => 0 - }).sum) - .sum + object Part2 extends Part { + override def roll(grid: Grid[Char]): Grid[Char] = + NaiverCycleFinder.find(grid, rollCycle)(1000000000) } @@ -119,7 +52,7 @@ object Day14 { lazy val input: String = scala.io.Source.fromInputStream(getClass.getResourceAsStream("day14.txt")).mkString.trim def main(args: Array[String]): Unit = { - println(totalLoad(parseGrid(input))) - println(totalLoad2(parseGrid(input))) + println(Part1.totalNorthLoad(parseGrid(input))) + println(Part2.totalNorthLoad(parseGrid(input))) } } diff --git a/src/test/scala/eu/sim642/adventofcode2023/Day14Test.scala b/src/test/scala/eu/sim642/adventofcode2023/Day14Test.scala index f6025ca9..593e35b6 100644 --- a/src/test/scala/eu/sim642/adventofcode2023/Day14Test.scala +++ b/src/test/scala/eu/sim642/adventofcode2023/Day14Test.scala @@ -18,18 +18,18 @@ class Day14Test extends AnyFunSuite { |#OO..#....""".stripMargin test("Part 1 examples") { - assert(totalLoad(parseGrid(exampleInput)) == 136) + assert(Part1.totalNorthLoad(parseGrid(exampleInput)) == 136) } test("Part 1 input answer") { - assert(totalLoad(parseGrid(input)) == 112048) + assert(Part1.totalNorthLoad(parseGrid(input)) == 112048) } test("Part 2 examples") { - assert(totalLoad2(parseGrid(exampleInput)) == 64) + assert(Part2.totalNorthLoad(parseGrid(exampleInput)) == 64) } test("Part 2 input answer") { - assert(totalLoad2(parseGrid(input)) == 105606) + assert(Part2.totalNorthLoad(parseGrid(input)) == 105606) } }