forked from matelaszlo/advent-of-code-scala
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathDay06.scala
54 lines (41 loc) · 1.8 KB
/
Day06.scala
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
package com.lmat.adventofcode.year2017
import com.lmat.adventofcode.year2017.Day06Definitions.Result
import com.lmat.adventofcode.CommonPuzzle
import com.lmat.util.Files.readResource
import scala.annotation.tailrec
object Day06Definitions {
case class Result(count: Int, size: Int)
}
object Day06 extends CommonPuzzle[Vector[Int], Result, Int, Int] {
type Blocks = Vector[Int]
override def parse(resource: String): Blocks =
readResource(resource).head.split("\\s+").map(_.toInt).toVector
override def preProcess(blocks: Blocks): Result = countRedistributionCycles(blocks)
override def part1(result: Result): Int = result.count
override def part2(result: Result): Int = result.size
def countRedistributionCycles(blocks: Blocks): Result = {
@tailrec
def countCycles(seen: Vector[Blocks], current: Blocks, count: Int): Result =
if (seen.contains(current)) Result(count, count - seen.indexOf(current))
else countCycles(seen :+ current, redistribute(current), count + 1)
countCycles(Vector(), blocks, 0)
}
/**
* To avoid simulating the redistribution we calculate the end state for each bank
* We check how many full rounds the redistribution does and who gets the rest
*/
def redistribute(blocks: Blocks): Blocks = {
val indexed = blocks.zipWithIndex
val (max, maxIndex) = indexed.maxBy(_._1)
val size = indexed.size
val rounds = max / size
val mod = max % size
val modIndices = (maxIndex + 1 to maxIndex + mod).map(_ % size)
indexed.map{
case (_, i) if i == maxIndex && modIndices.contains(i) => rounds + 1
case (_, i) if i == maxIndex => rounds
case (v, i) if modIndices.contains(i) => rounds + v + 1
case (v, _) => rounds + v
}
}
}