Add base structure and library stuff from last year
This commit is contained in:
commit
9017c4379c
6
.gitignore
vendored
Normal file
6
.gitignore
vendored
Normal file
|
@ -0,0 +1,6 @@
|
|||
.bloop
|
||||
.bsp
|
||||
target/
|
||||
project/project
|
||||
project/bloop.sbt
|
||||
project/metals.sbt
|
20
build.sbt
Normal file
20
build.sbt
Normal file
|
@ -0,0 +1,20 @@
|
|||
lazy val root = project
|
||||
.in(file("."))
|
||||
.settings(
|
||||
name := "aoc2021",
|
||||
version := "0.1.0",
|
||||
|
||||
scalaVersion := "3.1.0",
|
||||
scalacOptions ++= Seq(
|
||||
"-Yexplicit-nulls",
|
||||
"-language:strict-equality",
|
||||
"-deprecation",
|
||||
),
|
||||
libraryDependencies ++= Seq(
|
||||
"org.typelevel" %% "cats-core" % "2.6.1",
|
||||
"org.typelevel" %% "cats-effect" % "3.1.1",
|
||||
"org.typelevel" %% "kittens" % "3.0.0-M1",
|
||||
)
|
||||
)
|
||||
|
||||
Runtime / unmanagedSources += baseDirectory.value / "input"
|
1
project/build.properties
Normal file
1
project/build.properties
Normal file
|
@ -0,0 +1 @@
|
|||
sbt.version=1.5.3
|
2
project/plugins.sbt
Normal file
2
project/plugins.sbt
Normal file
|
@ -0,0 +1,2 @@
|
|||
//addSbtPlugin("ch.epfl.scala" % "sbt-scalafix" % "0.9.29")
|
||||
addSbtPlugin("org.scalameta" % "sbt-scalafmt" % "2.4.3")
|
6
src/main/scala/de.qwertyuiop.aoc/2021/day1.scala
Normal file
6
src/main/scala/de.qwertyuiop.aoc/2021/day1.scala
Normal file
|
@ -0,0 +1,6 @@
|
|||
package de.qwertyuiop.aoc.`2021`
|
||||
|
||||
import de.qwertyuiop.aoc.lib.*
|
||||
import cats.*, cats.implicits.given
|
||||
|
||||
def day1(using InputSource): Unit = ???
|
6
src/main/scala/de.qwertyuiop.aoc/2021/day10.scala
Normal file
6
src/main/scala/de.qwertyuiop.aoc/2021/day10.scala
Normal file
|
@ -0,0 +1,6 @@
|
|||
package de.qwertyuiop.aoc.`2021`
|
||||
|
||||
import de.qwertyuiop.aoc.lib.*
|
||||
import cats.*, cats.implicits.given
|
||||
|
||||
def day10(using InputSource): Unit = ???
|
6
src/main/scala/de.qwertyuiop.aoc/2021/day11.scala
Normal file
6
src/main/scala/de.qwertyuiop.aoc/2021/day11.scala
Normal file
|
@ -0,0 +1,6 @@
|
|||
package de.qwertyuiop.aoc.`2021`
|
||||
|
||||
import de.qwertyuiop.aoc.lib.*
|
||||
import cats.*, cats.implicits.given
|
||||
|
||||
def day11(using InputSource): Unit = ???
|
6
src/main/scala/de.qwertyuiop.aoc/2021/day12.scala
Normal file
6
src/main/scala/de.qwertyuiop.aoc/2021/day12.scala
Normal file
|
@ -0,0 +1,6 @@
|
|||
package de.qwertyuiop.aoc.`2021`
|
||||
|
||||
import de.qwertyuiop.aoc.lib.*
|
||||
import cats.*, cats.implicits.given
|
||||
|
||||
def day12(using InputSource): Unit = ???
|
6
src/main/scala/de.qwertyuiop.aoc/2021/day13.scala
Normal file
6
src/main/scala/de.qwertyuiop.aoc/2021/day13.scala
Normal file
|
@ -0,0 +1,6 @@
|
|||
package de.qwertyuiop.aoc.`2021`
|
||||
|
||||
import de.qwertyuiop.aoc.lib.*
|
||||
import cats.*, cats.implicits.given
|
||||
|
||||
def day13(using InputSource): Unit = ???
|
6
src/main/scala/de.qwertyuiop.aoc/2021/day14.scala
Normal file
6
src/main/scala/de.qwertyuiop.aoc/2021/day14.scala
Normal file
|
@ -0,0 +1,6 @@
|
|||
package de.qwertyuiop.aoc.`2021`
|
||||
|
||||
import de.qwertyuiop.aoc.lib.*
|
||||
import cats.*, cats.implicits.given
|
||||
|
||||
def day14(using InputSource): Unit = ???
|
6
src/main/scala/de.qwertyuiop.aoc/2021/day15.scala
Normal file
6
src/main/scala/de.qwertyuiop.aoc/2021/day15.scala
Normal file
|
@ -0,0 +1,6 @@
|
|||
package de.qwertyuiop.aoc.`2021`
|
||||
|
||||
import de.qwertyuiop.aoc.lib.*
|
||||
import cats.*, cats.implicits.given
|
||||
|
||||
def day15(using InputSource): Unit = ???
|
6
src/main/scala/de.qwertyuiop.aoc/2021/day16.scala
Normal file
6
src/main/scala/de.qwertyuiop.aoc/2021/day16.scala
Normal file
|
@ -0,0 +1,6 @@
|
|||
package de.qwertyuiop.aoc.`2021`
|
||||
|
||||
import de.qwertyuiop.aoc.lib.*
|
||||
import cats.*, cats.implicits.given
|
||||
|
||||
def day16(using InputSource): Unit = ???
|
6
src/main/scala/de.qwertyuiop.aoc/2021/day17.scala
Normal file
6
src/main/scala/de.qwertyuiop.aoc/2021/day17.scala
Normal file
|
@ -0,0 +1,6 @@
|
|||
package de.qwertyuiop.aoc.`2021`
|
||||
|
||||
import de.qwertyuiop.aoc.lib.*
|
||||
import cats.*, cats.implicits.given
|
||||
|
||||
def day17(using InputSource): Unit = ???
|
6
src/main/scala/de.qwertyuiop.aoc/2021/day18.scala
Normal file
6
src/main/scala/de.qwertyuiop.aoc/2021/day18.scala
Normal file
|
@ -0,0 +1,6 @@
|
|||
package de.qwertyuiop.aoc.`2021`
|
||||
|
||||
import de.qwertyuiop.aoc.lib.*
|
||||
import cats.*, cats.implicits.given
|
||||
|
||||
def day18(using InputSource): Unit = ???
|
6
src/main/scala/de.qwertyuiop.aoc/2021/day19.scala
Normal file
6
src/main/scala/de.qwertyuiop.aoc/2021/day19.scala
Normal file
|
@ -0,0 +1,6 @@
|
|||
package de.qwertyuiop.aoc.`2021`
|
||||
|
||||
import de.qwertyuiop.aoc.lib.*
|
||||
import cats.*, cats.implicits.given
|
||||
|
||||
def day19(using InputSource): Unit = ???
|
6
src/main/scala/de.qwertyuiop.aoc/2021/day2.scala
Normal file
6
src/main/scala/de.qwertyuiop.aoc/2021/day2.scala
Normal file
|
@ -0,0 +1,6 @@
|
|||
package de.qwertyuiop.aoc.`2021`
|
||||
|
||||
import de.qwertyuiop.aoc.lib.*
|
||||
import cats.*, cats.implicits.given
|
||||
|
||||
def day2(using InputSource): Unit = ???
|
6
src/main/scala/de.qwertyuiop.aoc/2021/day20.scala
Normal file
6
src/main/scala/de.qwertyuiop.aoc/2021/day20.scala
Normal file
|
@ -0,0 +1,6 @@
|
|||
package de.qwertyuiop.aoc.`2021`
|
||||
|
||||
import de.qwertyuiop.aoc.lib.*
|
||||
import cats.*, cats.implicits.given
|
||||
|
||||
def day20(using InputSource): Unit = ???
|
6
src/main/scala/de.qwertyuiop.aoc/2021/day21.scala
Normal file
6
src/main/scala/de.qwertyuiop.aoc/2021/day21.scala
Normal file
|
@ -0,0 +1,6 @@
|
|||
package de.qwertyuiop.aoc.`2021`
|
||||
|
||||
import de.qwertyuiop.aoc.lib.*
|
||||
import cats.*, cats.implicits.given
|
||||
|
||||
def day21(using InputSource): Unit = ???
|
6
src/main/scala/de.qwertyuiop.aoc/2021/day22.scala
Normal file
6
src/main/scala/de.qwertyuiop.aoc/2021/day22.scala
Normal file
|
@ -0,0 +1,6 @@
|
|||
package de.qwertyuiop.aoc.`2021`
|
||||
|
||||
import de.qwertyuiop.aoc.lib.*
|
||||
import cats.*, cats.implicits.given
|
||||
|
||||
def day22(using InputSource): Unit = ???
|
6
src/main/scala/de.qwertyuiop.aoc/2021/day23.scala
Normal file
6
src/main/scala/de.qwertyuiop.aoc/2021/day23.scala
Normal file
|
@ -0,0 +1,6 @@
|
|||
package de.qwertyuiop.aoc.`2021`
|
||||
|
||||
import de.qwertyuiop.aoc.lib.*
|
||||
import cats.*, cats.implicits.given
|
||||
|
||||
def day23(using InputSource): Unit = ???
|
6
src/main/scala/de.qwertyuiop.aoc/2021/day24.scala
Normal file
6
src/main/scala/de.qwertyuiop.aoc/2021/day24.scala
Normal file
|
@ -0,0 +1,6 @@
|
|||
package de.qwertyuiop.aoc.`2021`
|
||||
|
||||
import de.qwertyuiop.aoc.lib.*
|
||||
import cats.*, cats.implicits.given
|
||||
|
||||
def day24(using InputSource): Unit = ???
|
6
src/main/scala/de.qwertyuiop.aoc/2021/day25.scala
Normal file
6
src/main/scala/de.qwertyuiop.aoc/2021/day25.scala
Normal file
|
@ -0,0 +1,6 @@
|
|||
package de.qwertyuiop.aoc.`2021`
|
||||
|
||||
import de.qwertyuiop.aoc.lib.*
|
||||
import cats.*, cats.implicits.given
|
||||
|
||||
def day25(using InputSource): Unit = ???
|
6
src/main/scala/de.qwertyuiop.aoc/2021/day3.scala
Normal file
6
src/main/scala/de.qwertyuiop.aoc/2021/day3.scala
Normal file
|
@ -0,0 +1,6 @@
|
|||
package de.qwertyuiop.aoc.`2021`
|
||||
|
||||
import de.qwertyuiop.aoc.lib.*
|
||||
import cats.*, cats.implicits.given
|
||||
|
||||
def day3(using InputSource): Unit = ???
|
6
src/main/scala/de.qwertyuiop.aoc/2021/day4.scala
Normal file
6
src/main/scala/de.qwertyuiop.aoc/2021/day4.scala
Normal file
|
@ -0,0 +1,6 @@
|
|||
package de.qwertyuiop.aoc.`2021`
|
||||
|
||||
import de.qwertyuiop.aoc.lib.*
|
||||
import cats.*, cats.implicits.given
|
||||
|
||||
def day4(using InputSource): Unit = ???
|
6
src/main/scala/de.qwertyuiop.aoc/2021/day5.scala
Normal file
6
src/main/scala/de.qwertyuiop.aoc/2021/day5.scala
Normal file
|
@ -0,0 +1,6 @@
|
|||
package de.qwertyuiop.aoc.`2021`
|
||||
|
||||
import de.qwertyuiop.aoc.lib.*
|
||||
import cats.*, cats.implicits.given
|
||||
|
||||
def day5(using InputSource): Unit = ???
|
6
src/main/scala/de.qwertyuiop.aoc/2021/day6.scala
Normal file
6
src/main/scala/de.qwertyuiop.aoc/2021/day6.scala
Normal file
|
@ -0,0 +1,6 @@
|
|||
package de.qwertyuiop.aoc.`2021`
|
||||
|
||||
import de.qwertyuiop.aoc.lib.*
|
||||
import cats.*, cats.implicits.given
|
||||
|
||||
def day6(using InputSource): Unit = ???
|
6
src/main/scala/de.qwertyuiop.aoc/2021/day7.scala
Normal file
6
src/main/scala/de.qwertyuiop.aoc/2021/day7.scala
Normal file
|
@ -0,0 +1,6 @@
|
|||
package de.qwertyuiop.aoc.`2021`
|
||||
|
||||
import de.qwertyuiop.aoc.lib.*
|
||||
import cats.*, cats.implicits.given
|
||||
|
||||
def day7(using InputSource): Unit = ???
|
6
src/main/scala/de.qwertyuiop.aoc/2021/day8.scala
Normal file
6
src/main/scala/de.qwertyuiop.aoc/2021/day8.scala
Normal file
|
@ -0,0 +1,6 @@
|
|||
package de.qwertyuiop.aoc.`2021`
|
||||
|
||||
import de.qwertyuiop.aoc.lib.*
|
||||
import cats.*, cats.implicits.given
|
||||
|
||||
def day8(using InputSource): Unit = ???
|
6
src/main/scala/de.qwertyuiop.aoc/2021/day9.scala
Normal file
6
src/main/scala/de.qwertyuiop.aoc/2021/day9.scala
Normal file
|
@ -0,0 +1,6 @@
|
|||
package de.qwertyuiop.aoc.`2021`
|
||||
|
||||
import de.qwertyuiop.aoc.lib.*
|
||||
import cats.*, cats.implicits.given
|
||||
|
||||
def day9(using InputSource): Unit = ???
|
37
src/main/scala/de.qwertyuiop.aoc/Main.scala
Normal file
37
src/main/scala/de.qwertyuiop.aoc/Main.scala
Normal file
|
@ -0,0 +1,37 @@
|
|||
package de.qwertyuiop.aoc
|
||||
import de.qwertyuiop.aoc.lib._
|
||||
import de.qwertyuiop.aoc.`2021`._
|
||||
@main def runDay(inputDir: String, day: Int, sample: Int*): Unit =
|
||||
given InputSource = inputSource(inputDir, day, sample.headOption)
|
||||
day match {
|
||||
case 1 => day1
|
||||
case 2 => day2
|
||||
case 3 => day3
|
||||
case 4 => day4
|
||||
case 5 => day5
|
||||
case 6 => day6
|
||||
case 7 => day7
|
||||
case 8 => day8
|
||||
case 9 => day9
|
||||
case 10 => day10
|
||||
case 11 => day11
|
||||
case 12 => day12
|
||||
case 13 => day13
|
||||
case 14 => day14
|
||||
case 15 => day15
|
||||
case 16 => day16
|
||||
case 17 => day17
|
||||
case 18 => day18
|
||||
case 19 => day19
|
||||
case 20 => day20
|
||||
case 21 => day21
|
||||
case 22 => day22
|
||||
case 23 => day23
|
||||
case 24 => day24
|
||||
case 25 => day25
|
||||
case _ => println("No such day implemented")
|
||||
}
|
||||
|
||||
def inputSource(inputDir:String, day: Int, sample: Option[Int]) =
|
||||
sample.map(InputSource.SampleLocation(inputDir, day, _))
|
||||
.getOrElse(InputSource.Location(inputDir, day))
|
28
src/main/scala/de.qwertyuiop.aoc/lib/RingBuffer.scala
Normal file
28
src/main/scala/de.qwertyuiop.aoc/lib/RingBuffer.scala
Normal file
|
@ -0,0 +1,28 @@
|
|||
package de.qwertyuiop.aoc.lib
|
||||
|
||||
import scala.annotation.targetName
|
||||
|
||||
/* Wrap a vector to create a limited size ring buffer */
|
||||
|
||||
case class RingBuffer[A](underlying: Vector[A], maxSize: Int):
|
||||
/* pass through any methods to the underlying vector, except appending and
|
||||
* prepending single elements */
|
||||
export underlying.{ :+ => _, appended => _, +: => _, prepended => _, _ }
|
||||
|
||||
inline def full: Boolean = underlying.size == maxSize
|
||||
|
||||
@targetName("appended") def :+[B >: A](b: B): RingBuffer[B] =
|
||||
val appendedVec = (if full then underlying.tail else underlying) :+ b
|
||||
new RingBuffer(appendedVec, maxSize)
|
||||
|
||||
@targetName("prepended") def +:[B >: A](b: B): RingBuffer[B] =
|
||||
val prependedVec = b +: (if full then underlying.init else underlying)
|
||||
new RingBuffer(prependedVec, maxSize)
|
||||
|
||||
object RingBuffer:
|
||||
def apply[A](underlying: Vector[A], maxSize: Int): RingBuffer[A] =
|
||||
new RingBuffer(
|
||||
if underlying.size > maxSize then underlying.view.slice(0, maxSize).toVector
|
||||
else underlying,
|
||||
maxSize
|
||||
)
|
23
src/main/scala/de.qwertyuiop.aoc/lib/extensions.scala
Normal file
23
src/main/scala/de.qwertyuiop.aoc/lib/extensions.scala
Normal file
|
@ -0,0 +1,23 @@
|
|||
package de.qwertyuiop.aoc.lib
|
||||
|
||||
/* for splitting input with separator lines */
|
||||
extension [A](input: List[A])(using CanEqual[A,A])
|
||||
def split(separator: A, keepSeparator: Boolean = false): LazyList[List[A]] =
|
||||
input.span(_ != separator) match
|
||||
case (Nil, Nil) => LazyList()
|
||||
case (h, Nil) => LazyList(h)
|
||||
case (h, tail @ (_ :: t)) =>
|
||||
h #:: (if keepSeparator then tail else t).split(separator)
|
||||
|
||||
|
||||
/* Using -Yexplicit-nulls isn't really ready for use with the java standard
|
||||
* library. e.g. String doesn't have `@NotNull` annotations for its methods
|
||||
*/
|
||||
extension (s: String)
|
||||
def splitOnce(regex: String): Option[(String, String)] =
|
||||
s.split(regex, 2) match
|
||||
case Array(a, b) => Some((a.nn, b.nn))
|
||||
case _ => None
|
||||
|
||||
extension [K,V,W](map: Map[K,V])
|
||||
def mapValuesS(f: V => W): Map[K, W] = map.view.mapValues(f).toMap
|
31
src/main/scala/de.qwertyuiop.aoc/lib/inputs.scala
Normal file
31
src/main/scala/de.qwertyuiop.aoc/lib/inputs.scala
Normal file
|
@ -0,0 +1,31 @@
|
|||
package de.qwertyuiop.aoc.lib
|
||||
|
||||
import scala.io.Source
|
||||
|
||||
enum InputSource:
|
||||
case Location(inputDir: String, day: Int)
|
||||
case Fixed(lines: List[String])
|
||||
case SampleLocation(inputDir: String, day: Int, sample: Int)
|
||||
|
||||
def inputLines(using src: InputSource): Iterator[String] =
|
||||
src match
|
||||
case InputSource.Location(inputDir, day) => scala.io.Source.fromFile(s"${inputDir}/day${day}.txt").getLines
|
||||
case InputSource.Fixed(input) => input.iterator
|
||||
case InputSource.SampleLocation(inputDir, day, sample) => scala.io.Source.fromFile(s"${inputDir}/day${day}-sample${sample}.txt").getLines
|
||||
|
||||
|
||||
def simpleInput(using l: InputSource): String = inputLines.mkString
|
||||
|
||||
def input[A](format: String => A = identity)(using l: InputSource): List[A] =
|
||||
inputF(format)(List)
|
||||
|
||||
def inputF[A, C[_]](format: String => A = identity)(coll: collection.Factory[A, C[A]])(using l: InputSource): C[A] =
|
||||
inputLines.map(format).to(coll)
|
||||
|
||||
def flatInput[A](format: String => List[A] = List.apply)(using l: InputSource): List[A] =
|
||||
flatInputF(format)(List)
|
||||
|
||||
def flatInputF[A, C[_]](format: String => IterableOnce[A] = identity)(coll: collection.Factory[A, C[A]])(using l: InputSource): C[A] =
|
||||
inputLines.flatMap(format).to(coll)
|
||||
|
||||
def boolChar(trueChar: Char): String => Vector[Boolean] = _.map(_ == trueChar).toVector
|
9
src/main/scala/de.qwertyuiop.aoc/lib/misc.scala
Normal file
9
src/main/scala/de.qwertyuiop.aoc/lib/misc.scala
Normal file
|
@ -0,0 +1,9 @@
|
|||
package de.qwertyuiop.aoc.lib
|
||||
|
||||
import scala.collection.mutable
|
||||
|
||||
def memoize[I, O](f: I => O): I => O = new mutable.HashMap[I, O]() {self =>
|
||||
override def apply(key: I) = self.synchronized(getOrElseUpdate(key, f(key)))
|
||||
}
|
||||
|
||||
def repeat[T](n: Int)(f: T => T): T => T = Function.chain(Seq.fill(n)(f))
|
145
src/main/scala/de.qwertyuiop.aoc/lib/vectors.scala
Normal file
145
src/main/scala/de.qwertyuiop.aoc/lib/vectors.scala
Normal file
|
@ -0,0 +1,145 @@
|
|||
package de.qwertyuiop.aoc.lib
|
||||
|
||||
import cats.*, cats.implicits.given
|
||||
import cats.derived.semiauto
|
||||
|
||||
object Vectors:
|
||||
import scala.Numeric.Implicits.given
|
||||
import scala.compiletime.ops.int.*
|
||||
import Directions.*
|
||||
|
||||
opaque type Vec2D[T] = (T, T)
|
||||
opaque type Vec3D[T] = (T, T, T)
|
||||
opaque type Vec4D[T] = (T, T, T, T)
|
||||
|
||||
def Vec2D[T](x: T, y: T): Vec2D[T] = (x,y)
|
||||
def Vec3D[T](x: T, y: T, z: T): Vec3D[T] = (x,y,z)
|
||||
def Vec4D[T](x: T, y: T, z: T, w: T): Vec4D[T] = (x,y,z,w)
|
||||
|
||||
trait Vec[T]:
|
||||
extension (v: T)
|
||||
def +(w: T): T
|
||||
def neighbours: List[T]
|
||||
|
||||
given [T : Show]: Show[Vec2D[T]] with
|
||||
def show(v: Vec2D[T]): String = show"Vec2D(${v._1}, ${v._2})"
|
||||
given [T : Show]: Show[Vec3D[T]] with
|
||||
def show(v: Vec3D[T]): String = show"Vec3D(${v._1}, ${v._2}, ${v._3})"
|
||||
given [T : Show]: Show[Vec4D[T]] with
|
||||
def show(v: Vec4D[T]): String = show"Vec4D(${v._1}, ${v._2}, ${v._3}, ${v._4})"
|
||||
|
||||
given [T: Numeric]: Vec[Vec2D[T]] with
|
||||
extension (v: Vec2D[T])
|
||||
def +(w: Vec2D[T]): Vec2D[T] = (v._1 + w._1, v._2 + w._2)
|
||||
def -(w: Vec2D[T]): Vec2D[T] = (v._1 - w._1, v._2 - w._2)
|
||||
def *(x: T): Vec2D[T] = (v._1 * x, v._2 * x)
|
||||
|
||||
def x: T = v._1
|
||||
def y: T = v._2
|
||||
|
||||
def rot(deg: Dir): Vec2D[T] = deg match
|
||||
case North => (-v._2, v._1)
|
||||
case West => (-v._1, -v._2)
|
||||
case South => (v._2, -v._1)
|
||||
case East => v
|
||||
|
||||
def left(deg: Int): Vec2D[T] = repeat[Vec2D[T]](deg / 90)(_.rotLeft)(v)
|
||||
def right(deg: Int): Vec2D[T] = repeat[Vec2D[T]](deg / 90)(_.rotRight)(v)
|
||||
|
||||
def rotLeft: Vec2D[T] = (-v._2, v._1)
|
||||
def rotRight: Vec2D[T] = (v._2, -v._1)
|
||||
|
||||
def move(dir: Dir, dist: T): Vec2D[T] = dir match
|
||||
case North => (v._1, v._2 + dist)
|
||||
case South => (v._1, v._2 - dist)
|
||||
case East => (v._1 + dist, v._2)
|
||||
case West => (v._1 - dist, v._2)
|
||||
|
||||
def manhattan: T = v._1.abs + v._2.abs
|
||||
def neighbours: List[Vec2D[T]] =
|
||||
neighbourCoords(2).map(n => v + (n(0), n(1)))
|
||||
|
||||
given [T: Monoid]: Monoid[Vec2D[T]] = semiauto.monoid
|
||||
given [T: Monoid]: Monoid[Vec3D[T]] = semiauto.monoid
|
||||
given [T: Monoid]: Monoid[Vec4D[T]] = semiauto.monoid
|
||||
|
||||
|
||||
given [T: Numeric]: Vec[Vec3D[T]] with
|
||||
extension (v: Vec3D[T])
|
||||
def +(w: Vec3D[T]): Vec3D[T] = (v._1 + w._1, v._2 + w._2, v._3 + w._3)
|
||||
def neighbours: List[Vec3D[T]] =
|
||||
neighbourCoords(3).map(n => v + (n(0), n(1), n(2)))
|
||||
|
||||
def x: T = v._1
|
||||
def y: T = v._2
|
||||
def z: T = v._3
|
||||
|
||||
given [T: Numeric]: Vec[Vec4D[T]] with
|
||||
extension (v: Vec4D[T])
|
||||
def +(u: Vec4D[T]): Vec4D[T] = (v._1 + u._1, v._2 + u._2, v._3 + u._3, v._4 + u._4)
|
||||
def neighbours: List[Vec4D[T]] =
|
||||
neighbourCoords(4).map(n => v + (n(0), n(1), n(2), n(3)))
|
||||
|
||||
def x: T = v._1
|
||||
def y: T = v._2
|
||||
def z: T = v._3
|
||||
def w: T = v._4
|
||||
|
||||
|
||||
/* compute these only once per type and dimension*/
|
||||
import scala.collection.mutable
|
||||
private var _neighbourCache = mutable.Map[(Numeric[_], Int), List[List[_]]]()
|
||||
def neighbourCoords[T](dim: Int)(using n: Numeric[T]): List[List[T]] =
|
||||
_neighbourCache.get((n, dim)) match
|
||||
case None =>
|
||||
val self = List.fill(dim)(n.zero)
|
||||
val neighs = List.fill(dim)(List(-n.one, n.zero, n.one)).sequence[List, T]
|
||||
.filter(_ != self)
|
||||
_neighbourCache.put((n, dim), neighs)
|
||||
neighs
|
||||
case Some(neighs) => neighs.asInstanceOf[List[List[T]]]
|
||||
|
||||
object Directions:
|
||||
opaque type Dir = Int
|
||||
val East: Dir = 0
|
||||
val North: Dir = 90
|
||||
val West: Dir = 180
|
||||
val South: Dir = 270
|
||||
|
||||
extension (c: Char)
|
||||
def cardinal: Dir = c match
|
||||
case 'E' => East
|
||||
case 'N' => North
|
||||
case 'W' => West
|
||||
case 'S' => South
|
||||
|
||||
def Dir(deg: Int): Dir = (deg % 360 + 360) % 360
|
||||
|
||||
private val rotationOrder = Vector(North, West, South, East, North, West)
|
||||
|
||||
extension (dir: Dir)
|
||||
def +(deg: Int|Dir): Dir = (dir + deg) % 360
|
||||
def -(deg: Int|Dir): Dir = ((dir - deg) % 360 + 360) % 360
|
||||
def unary_- : Dir = 360 - dir
|
||||
def str: String = dir match
|
||||
case East => "East"
|
||||
case North => "North"
|
||||
case West => "West"
|
||||
case South => "South"
|
||||
|
||||
def rotLeft: Dir = rotationOrder(rotationOrder.indexOf(dir) + 1)
|
||||
def rotRight: Dir = rotationOrder(rotationOrder.lastIndexOf(dir) - 1)
|
||||
def flip: Dir = rotationOrder(rotationOrder.indexOf(dir) + 2)
|
||||
|
||||
def flipHor: Dir = dir match
|
||||
case West => East
|
||||
case East => West
|
||||
case o => o
|
||||
|
||||
def flipVert: Dir = dir match
|
||||
case North => South
|
||||
case South => North
|
||||
case o => o
|
||||
|
||||
given Show[Dir] with
|
||||
def show(d: Dir): String = d.str
|
Loading…
Reference in a new issue