Skip to content

Commit

Permalink
Clean up 2023 day 14
Browse files Browse the repository at this point in the history
  • Loading branch information
sim642 committed Dec 14, 2023
1 parent 63522f9 commit cf500a2
Show file tree
Hide file tree
Showing 2 changed files with 35 additions and 102 deletions.
129 changes: 31 additions & 98 deletions src/main/scala/eu/sim642/adventofcode2023/Day14.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}


Expand All @@ -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)))
}
}
8 changes: 4 additions & 4 deletions src/test/scala/eu/sim642/adventofcode2023/Day14Test.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
}

0 comments on commit cf500a2

Please sign in to comment.