-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathDay14.scala
59 lines (44 loc) · 1.98 KB
/
Day14.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
55
56
57
58
59
package com.lmat.adventofcode.year2017
import com.lmat.adventofcode.CommonPuzzle
import com.lmat.adventofcode.year2017.Day10.{calculateLengths, knotHash}
import com.lmat.util.Files.readResource
import com.lmat.util.Strings.leftPad
import scala.annotation.tailrec
object Day14 extends CommonPuzzle[String, Seq[String], Int, Int] {
override def parse(resource: String): String = readResource(resource).head
val hashSize: Int = 256
val hashRounds: Int = 64
val hash: String => String = input => knotHash(hashSize, hashRounds)(calculateLengths(input))
val gridSize:Int = 128
override def preProcess(key: String): Seq[String] = calculateGrid(gridSize, hash)(key)
override def part1(grid: Seq[String]): Int =
grid.map(_.count(_ == '1')).sum
def calculateGrid(gridSize: Int, hash: String => String)(key: String): Seq[String] =
for (row <- 0 until gridSize)
yield hextoBin(hash(s"$key-$row"))
def hextoBin(hex: String): String =
leftPad(BigInt(hex, 16).toString(2))( '0', 128)
override def part2(grid: Seq[String]): Int =
countRegions(grid)
def countRegions(grid: Seq[String]): Int = {
case class Position(row: Int, column: Int)
val positions = for {
row <- grid.indices
column <- 0 until grid.head.length if grid(row)(column) == '1'
} yield Position(row, column)
@tailrec
def countRegions(positions: Seq[Position], acc: Int): Int = positions match {
case Seq() => acc
case h +: tail => countRegions(removeNeighbours(tail, Seq(h)), acc + 1)
}
@tailrec
def removeNeighbours(positions: Seq[Position], bases: Seq[Position]): Seq[Position] = {
val (removed, rest) = positions.partition(p1 => bases.exists(p2 => areNeighbours(p1, p2)))
if (removed.isEmpty) rest
else removeNeighbours(rest, removed)
}
def areNeighbours(p1: Position, p2: Position): Boolean =
Math.abs(p1.row - p2.row) + Math.abs(p1.column - p2.column) == 1
countRegions(positions, 0)
}
}