diff --git a/2015/src/main/scala/aoc2015/Day03.scala b/2015/src/main/scala/aoc2015/Day03.scala index 09775cae..f3d51807 100644 --- a/2015/src/main/scala/aoc2015/Day03.scala +++ b/2015/src/main/scala/aoc2015/Day03.scala @@ -1,7 +1,7 @@ package aoc2015 import nmcb.* -import nmcb.pos.* +import nmcb.pos.{*, given} object Day03 extends AoC: diff --git a/2015/src/main/scala/aoc2015/Day11.scala b/2015/src/main/scala/aoc2015/Day11.scala index f0e22233..4afdc25f 100644 --- a/2015/src/main/scala/aoc2015/Day11.scala +++ b/2015/src/main/scala/aoc2015/Day11.scala @@ -31,6 +31,8 @@ object Day11 extends AoC: case Zero extends Carry(0x00) case One extends Carry(value = 0x01) + given CanEqual[Carry, Carry] = CanEqual.derived + val MinValue: Char = 'a' val MaxValue: Char = 'z' val ValueRange: Char = (MaxValue - MinValue + 1).toChar diff --git a/2015/src/main/scala/aoc2015/Day12.scala b/2015/src/main/scala/aoc2015/Day12.scala index da7a2ff1..69b8c1c0 100644 --- a/2015/src/main/scala/aoc2015/Day12.scala +++ b/2015/src/main/scala/aoc2015/Day12.scala @@ -39,6 +39,8 @@ object Day12 extends AoC: case class Num(underlying: Long) extends Json case class Arr(underlying: List[Json]) extends Json case class Obj(underlying: Map[String,Json]) extends Json + + given CanEqual[Json, Json] = CanEqual.derived def solve(json: Json, objValueFilter: Json => Boolean = _ => true): Long = def loop(acc: Long, json: Json): Long = diff --git a/2015/src/main/scala/aoc2015/Day21.scala b/2015/src/main/scala/aoc2015/Day21.scala index 759b86f2..2c434799 100644 --- a/2015/src/main/scala/aoc2015/Day21.scala +++ b/2015/src/main/scala/aoc2015/Day21.scala @@ -9,7 +9,7 @@ object Day21 extends AoC: object Player: def equip(points: Int, weapon: Weapon, armor: Option[Armor], rings: Seq[Ring]): Player = assert(rings.size <= 2, "max 2 rings") - assert(rings == rings.distinct, "max one of a kind") + assert((rings diff rings.distinct).isEmpty, "max one of a kind") Player( points = points , damage = weapon.damage + rings.map(_.damage).sum , armor = armor.map(_.armor).getOrElse(0) + rings.map(_.armor).sum @@ -41,6 +41,8 @@ object Day21 extends AoC: enum Outcome: case Won case Lost + + given CanEqual[Outcome, Outcome] = CanEqual.derived case class Game(player: Player, boss: Player): import Outcome.* @@ -67,7 +69,7 @@ object Day21 extends AoC: w <- Weapon.values.toList a <- Armor.values.toList.map(Option(_)) :+ Option.empty[Armor] rs <- Ring.values.toList.map(List(_)) ++ Ring.values.toList.combinations(2) ++ List(List.empty[Ring]) - if rs == rs.distinct + if (rs diff rs.distinct).isEmpty yield Player.equip(100, w, a, rs) diff --git a/2015/src/main/scala/aoc2015/Day22.scala b/2015/src/main/scala/aoc2015/Day22.scala index 4ff1fbd9..91d642ae 100644 --- a/2015/src/main/scala/aoc2015/Day22.scala +++ b/2015/src/main/scala/aoc2015/Day22.scala @@ -12,6 +12,8 @@ object Day22 extends AoC: case Recharge extends Spell(229, 5) import Spell.* + + given CanEqual[Spell, Spell] = CanEqual.derived val Spells = Set(MagicMissile, Drain, Shield, Poison, Recharge) diff --git a/2016/src/main/scala/aoc2016/Day01.scala b/2016/src/main/scala/aoc2016/Day01.scala index 75c80eef..41016071 100644 --- a/2016/src/main/scala/aoc2016/Day01.scala +++ b/2016/src/main/scala/aoc2016/Day01.scala @@ -1,7 +1,7 @@ package aoc2016 import nmcb.* -import nmcb.pos.* +import nmcb.pos.{*, given} import scala.annotation.tailrec import scala.util.Try diff --git a/2016/src/main/scala/aoc2016/Day10.scala b/2016/src/main/scala/aoc2016/Day10.scala index ce8b32b5..62061382 100644 --- a/2016/src/main/scala/aoc2016/Day10.scala +++ b/2016/src/main/scala/aoc2016/Day10.scala @@ -1,6 +1,8 @@ package aoc2016 import nmcb.* + +import scala.CanEqual.derived import scala.collection.mutable object Day10 extends AoC: @@ -10,6 +12,8 @@ object Day10 extends AoC: case Out(override val index: Int) extends Target(index) import Target.* + + given CanEqual[Target, Target] = CanEqual.derived enum Inst: case Init(bot: Bot, value: Int) diff --git a/2016/src/main/scala/aoc2016/Day13.scala b/2016/src/main/scala/aoc2016/Day13.scala index 573e0ec6..ebac03db 100644 --- a/2016/src/main/scala/aoc2016/Day13.scala +++ b/2016/src/main/scala/aoc2016/Day13.scala @@ -1,7 +1,7 @@ package aoc2016 import nmcb.* -import nmcb.pos.* +import nmcb.pos.{*, given} import scala.collection.* import scala.collection.immutable.Map diff --git a/2016/src/main/scala/aoc2016/Day17.scala b/2016/src/main/scala/aoc2016/Day17.scala index 82f946f8..c7529491 100644 --- a/2016/src/main/scala/aoc2016/Day17.scala +++ b/2016/src/main/scala/aoc2016/Day17.scala @@ -2,7 +2,7 @@ package aoc2016 import nmcb.* import nmcb.predef.* -import nmcb.pos.* +import nmcb.pos.{*, given} import java.security.MessageDigest import scala.collection.* diff --git a/2016/src/main/scala/aoc2016/Day22.scala b/2016/src/main/scala/aoc2016/Day22.scala index 0148c4ec..aca040c6 100644 --- a/2016/src/main/scala/aoc2016/Day22.scala +++ b/2016/src/main/scala/aoc2016/Day22.scala @@ -1,7 +1,7 @@ package aoc2016 import nmcb.* -import nmcb.pos.* +import nmcb.pos.{*, given} object Day22 extends AoC: @@ -16,6 +16,8 @@ object Day22 extends AoC: else if isMassive then '#' else '.' + given CanEqual[Node, Node] = CanEqual.derived + val nodes: Map[Pos,Node] = lines .filter(_.startsWith("/dev/grid/node")) @@ -24,7 +26,7 @@ object Day22 extends AoC: Pos.of(x, y) -> Node(used, avail) .toMap - def viable(nodes: Map[Pos,Node]): Vector[(Node,Node)] = + def viable(nodes: Map[Pos, Node]): Vector[(Node, Node)] = for (_,a) <- nodes.toVector (_,b) <- nodes.toVector diff --git a/2016/src/main/scala/aoc2016/Day24.scala b/2016/src/main/scala/aoc2016/Day24.scala index f29827cf..156be145 100644 --- a/2016/src/main/scala/aoc2016/Day24.scala +++ b/2016/src/main/scala/aoc2016/Day24.scala @@ -1,7 +1,7 @@ package aoc2016 import nmcb.* -import nmcb.pos.* +import nmcb.pos.{*, given} object Day24 extends AoC: diff --git a/2017/src/main/scala/aoc2017/Day03.scala b/2017/src/main/scala/aoc2017/Day03.scala index 5a6bc2b2..74ebe47d 100644 --- a/2017/src/main/scala/aoc2017/Day03.scala +++ b/2017/src/main/scala/aoc2017/Day03.scala @@ -1,7 +1,7 @@ package aoc2017 import nmcb.* -import nmcb.pos.* +import nmcb.pos.{*, given} import nmcb.predef.* import scala.annotation.tailrec diff --git a/2017/src/main/scala/aoc2017/Day06.scala b/2017/src/main/scala/aoc2017/Day06.scala index 8c08a37c..c5e7ab50 100644 --- a/2017/src/main/scala/aoc2017/Day06.scala +++ b/2017/src/main/scala/aoc2017/Day06.scala @@ -41,6 +41,8 @@ object Day06 extends AoC: loop(next, seen :+ current) loop(this) + given CanEqual[Area, Area] = CanEqual.derived + override lazy val answer1: Int = Area(banks).redistribute.size - 1 diff --git a/2017/src/main/scala/aoc2017/Day11.scala b/2017/src/main/scala/aoc2017/Day11.scala index 1eedf295..c180fa34 100644 --- a/2017/src/main/scala/aoc2017/Day11.scala +++ b/2017/src/main/scala/aoc2017/Day11.scala @@ -14,6 +14,8 @@ object Day11 extends AoC: case NW import Dir.* + + given CanEqual[Dir, Dir] = CanEqual.derived case class Hex(x: Int, y: Int, z: Int): assert(x + y + z == 0) diff --git a/2017/src/main/scala/aoc2017/Day14.scala b/2017/src/main/scala/aoc2017/Day14.scala index efd37062..d671803b 100644 --- a/2017/src/main/scala/aoc2017/Day14.scala +++ b/2017/src/main/scala/aoc2017/Day14.scala @@ -1,7 +1,7 @@ package aoc2017 import nmcb.* -import nmcb.pos.* +import nmcb.pos.{*, given} import Day10.KnotHash import Day12.Dijkstra diff --git a/2017/src/main/scala/aoc2017/Day19.scala b/2017/src/main/scala/aoc2017/Day19.scala index 5102957b..b91e8de1 100644 --- a/2017/src/main/scala/aoc2017/Day19.scala +++ b/2017/src/main/scala/aoc2017/Day19.scala @@ -1,7 +1,7 @@ package aoc2017 import nmcb.* -import nmcb.pos.* +import nmcb.pos.{*, given} import scala.annotation.tailrec diff --git a/2017/src/main/scala/aoc2017/Day22.scala b/2017/src/main/scala/aoc2017/Day22.scala index 70ae85b9..a43a1d11 100644 --- a/2017/src/main/scala/aoc2017/Day22.scala +++ b/2017/src/main/scala/aoc2017/Day22.scala @@ -1,7 +1,7 @@ package aoc2017 import nmcb.* -import nmcb.pos.* +import nmcb.pos.{*, given} import nmcb.predef.* object Day22 extends AoC: @@ -10,6 +10,8 @@ object Day22 extends AoC: case Clean, Infected, Weakened, Flagged import Status.* + + given CanEqual[Status, Status] = CanEqual.derived case class Carrier(nodes: Map[Pos,Status], current: Pos, dir: Dir, infected: Int = 0): diff --git a/2017/src/main/scala/aoc2017/Day25.scala b/2017/src/main/scala/aoc2017/Day25.scala index 7944e269..56bd2bd1 100644 --- a/2017/src/main/scala/aoc2017/Day25.scala +++ b/2017/src/main/scala/aoc2017/Day25.scala @@ -9,6 +9,8 @@ object Day25 extends AoC: case L, R import Move.* + + given CanEqual[Move, Move] = CanEqual.derived type State = String type Value = Int diff --git a/2017/src/test/scala/aoc2017/Test2017.scala b/2017/src/test/scala/aoc2017/Test2017.scala index be51a3d6..ba8cc3b2 100644 --- a/2017/src/test/scala/aoc2017/Test2017.scala +++ b/2017/src/test/scala/aoc2017/Test2017.scala @@ -3,6 +3,8 @@ package aoc2017 import org.scalatest.funsuite.AnyFunSuite class Test2017 extends AnyFunSuite: + + given CanEqual[Any, Any] = CanEqual.derived test("Day 1: Inverse Captcha"): assertResult(1069)(Day01.answer1) diff --git a/2018/src/main/scala/aoc2018/Day02.scala b/2018/src/main/scala/aoc2018/Day02.scala index f7991b3e..8a8a9063 100644 --- a/2018/src/main/scala/aoc2018/Day02.scala +++ b/2018/src/main/scala/aoc2018/Day02.scala @@ -18,6 +18,9 @@ object Day02 extends AoC: idLettersWith(3) >= 1 object Box: + + given CanEqual[Box, Box] = CanEqual.derived + val IdCharSet: String = "abcdefghijklmnopqrstuvwxyz" def fromString(id: String): Box = Box(id) diff --git a/2018/src/main/scala/aoc2018/Day03.scala b/2018/src/main/scala/aoc2018/Day03.scala index d40c0841..13c30734 100644 --- a/2018/src/main/scala/aoc2018/Day03.scala +++ b/2018/src/main/scala/aoc2018/Day03.scala @@ -1,7 +1,7 @@ package aoc2018 import nmcb.* -import nmcb.pos.* +import nmcb.pos.{*, given} object Day03 extends AoC: diff --git a/2018/src/main/scala/aoc2018/Day04.scala b/2018/src/main/scala/aoc2018/Day04.scala index 907badbd..d6f9c905 100644 --- a/2018/src/main/scala/aoc2018/Day04.scala +++ b/2018/src/main/scala/aoc2018/Day04.scala @@ -12,6 +12,8 @@ object Day04 extends AoC: import Event.* + given CanEqual[Event, Event] = CanEqual.derived + type Timestamp = String case class Record(timestamp: Timestamp, event: Event): diff --git a/2018/src/main/scala/aoc2018/Day06.scala b/2018/src/main/scala/aoc2018/Day06.scala index 8f872831..4f10da22 100644 --- a/2018/src/main/scala/aoc2018/Day06.scala +++ b/2018/src/main/scala/aoc2018/Day06.scala @@ -1,7 +1,7 @@ package aoc2018 import nmcb.* -import nmcb.pos.* +import nmcb.pos.{*, given} import scala.collection.+: import scala.collection.immutable.Vector diff --git a/2018/src/main/scala/aoc2018/Day10.scala b/2018/src/main/scala/aoc2018/Day10.scala index 774f548a..48fc713b 100644 --- a/2018/src/main/scala/aoc2018/Day10.scala +++ b/2018/src/main/scala/aoc2018/Day10.scala @@ -1,7 +1,7 @@ package aoc2018 import nmcb.* -import nmcb.pos.* +import nmcb.pos.{*, given} import scala.annotation.* import scala.math.Integral.Implicits.* diff --git a/2018/src/main/scala/aoc2018/Day11.scala b/2018/src/main/scala/aoc2018/Day11.scala index 2ecd8f35..246033f8 100644 --- a/2018/src/main/scala/aoc2018/Day11.scala +++ b/2018/src/main/scala/aoc2018/Day11.scala @@ -1,7 +1,7 @@ package aoc2018 import nmcb.* -import nmcb.pos.* +import nmcb.pos.{*, given} import scala.collection.* diff --git a/2018/src/main/scala/aoc2018/Day13.scala b/2018/src/main/scala/aoc2018/Day13.scala index c492eaea..cdc2dfb4 100644 --- a/2018/src/main/scala/aoc2018/Day13.scala +++ b/2018/src/main/scala/aoc2018/Day13.scala @@ -50,6 +50,8 @@ object Day13 extends AoC: case Straight => Right case Right => Left + given CanEqual[Turn, Turn] = CanEqual.derived + case class Cart(pos: Pos, dir: Dir, atIntersection: Turn = Turn.Left): def move(grid: Grid): Cart = diff --git a/2018/src/main/scala/aoc2018/Day15.scala b/2018/src/main/scala/aoc2018/Day15.scala index fef0b2d5..596c8159 100644 --- a/2018/src/main/scala/aoc2018/Day15.scala +++ b/2018/src/main/scala/aoc2018/Day15.scala @@ -1,7 +1,7 @@ package aoc2018 import nmcb.* -import nmcb.pos.* +import nmcb.pos.{*, given} import scala.annotation.tailrec import scala.util.Try @@ -22,10 +22,13 @@ object Day15 extends AoC: import FighterType.* + given CanEqual[FighterType, FighterType] = CanEqual.derived + case class Fighter(fighterType: FighterType, pos: Pos, hitPoints: Int = 200, attackPower: Int = 3) - given Ordering[Pos] = Ordering.by(_.toTuple.swap) - given Ordering[Fighter] = Ordering.by(_.pos) + given Ordering[Pos] = Ordering.by(_.toTuple.swap) + given Ordering[Fighter] = Ordering.by(_.pos) + given CanEqual[Fighter, Fighter] = CanEqual.derived def targetsOf(fighter: Fighter)(using fighters: List[Fighter]): Set[Fighter] = fighters.filter(_.fighterType == fighter.fighterType.target).toSet diff --git a/2018/src/main/scala/aoc2018/Day16.scala b/2018/src/main/scala/aoc2018/Day16.scala index c2285029..08941cf8 100644 --- a/2018/src/main/scala/aoc2018/Day16.scala +++ b/2018/src/main/scala/aoc2018/Day16.scala @@ -63,6 +63,8 @@ object Day16 extends AoC: case EQRI => mem.setRI(a, b, c, (a: Int) => (b: Int) => if a == b then 1 else 0) case EQRR => mem.setRR(a, b, c, (a: Int) => (b: Int) => if a == b then 1 else 0) + given CanEqual[Inst, Inst] = CanEqual.derived + type Test = (Mem, Codes, Mem) extension (test: Test) diff --git a/2018/src/main/scala/aoc2018/Day17.scala b/2018/src/main/scala/aoc2018/Day17.scala index 4ed80c82..83689227 100644 --- a/2018/src/main/scala/aoc2018/Day17.scala +++ b/2018/src/main/scala/aoc2018/Day17.scala @@ -1,7 +1,7 @@ package aoc2018 import nmcb.* -import nmcb.pos.* +import nmcb.pos.{*, given} object Day17 extends AoC: @@ -16,6 +16,8 @@ object Day17 extends AoC: case Stopped case Flowing + given CanEqual[Stream, Stream] = CanEqual.derived + import Stream.* import Iterator.* diff --git a/2018/src/main/scala/aoc2018/Day18.scala b/2018/src/main/scala/aoc2018/Day18.scala index ca0dc639..b1b592c1 100644 --- a/2018/src/main/scala/aoc2018/Day18.scala +++ b/2018/src/main/scala/aoc2018/Day18.scala @@ -1,7 +1,7 @@ package aoc2018 import nmcb.* -import nmcb.pos.* +import nmcb.pos.{*, given} import nmcb.predef.* import scala.collection.* diff --git a/2018/src/main/scala/aoc2018/Day22.scala b/2018/src/main/scala/aoc2018/Day22.scala index e9598e0e..5956c343 100644 --- a/2018/src/main/scala/aoc2018/Day22.scala +++ b/2018/src/main/scala/aoc2018/Day22.scala @@ -12,6 +12,8 @@ object Day22 extends AoC: case Wet extends RegionType(1) case Narrow extends RegionType(2) + given CanEqual[RegionType, RegionType] = CanEqual.derived + case class Region(x: Int, y: Int): infix def +(x: Int, y: Int): Region = copy(x = this.x + x, y = this.y + y) infix def manhattan(that: Region): Int = (x - that.x).abs + (y - that.y).abs @@ -23,6 +25,8 @@ object Day22 extends AoC: object Region: + + given CanEqual[Region, Region] = CanEqual.derived val depth: Int = 11817 val mouth: Region = Region(0, 0) @@ -55,6 +59,8 @@ object Day22 extends AoC: case Torch case ClimbingGear + given CanEqual[Tool, Tool] = CanEqual.derived + import RegionType.* import Tool.* diff --git a/2018/src/main/scala/aoc2018/Day23.scala b/2018/src/main/scala/aoc2018/Day23.scala index d66e5a36..f71f3b5b 100644 --- a/2018/src/main/scala/aoc2018/Day23.scala +++ b/2018/src/main/scala/aoc2018/Day23.scala @@ -14,6 +14,8 @@ object Day23 extends AoC: infix def hasOverlappingRadiusWith(that: Bot): Boolean = loc.manhattan(that.loc) <= radius + that.radius + given CanEqual[Bot, Bot] = CanEqual.derived + val bots: Set[Bot] = lines .collect: diff --git a/2018/src/main/scala/aoc2018/Day24.scala b/2018/src/main/scala/aoc2018/Day24.scala index 052124ff..e2cdbe8c 100644 --- a/2018/src/main/scala/aoc2018/Day24.scala +++ b/2018/src/main/scala/aoc2018/Day24.scala @@ -13,6 +13,8 @@ object Day24 extends AoC: case Infection import Army.* + + given CanEqual[Army, Army] = CanEqual.derived type AttackKind = String diff --git a/2019/src/main/scala/aoc2019/Day03.scala b/2019/src/main/scala/aoc2019/Day03.scala index 76d93d07..c9c34413 100644 --- a/2019/src/main/scala/aoc2019/Day03.scala +++ b/2019/src/main/scala/aoc2019/Day03.scala @@ -1,7 +1,7 @@ package aoc2019 import nmcb.* -import nmcb.pos.* +import nmcb.pos.{*, given} object Day03 extends AoC: diff --git a/2019/src/main/scala/aoc2019/Day08.scala b/2019/src/main/scala/aoc2019/Day08.scala index 27fed520..5093a588 100644 --- a/2019/src/main/scala/aoc2019/Day08.scala +++ b/2019/src/main/scala/aoc2019/Day08.scala @@ -11,6 +11,8 @@ object Day08 extends AoC: type Line[A] = List[A] case class Layer[A](digs: List[Line[A]]): + + given CanEqual[A, Dig] = CanEqual.derived def count(d: Dig): Int = digs.foldLeft(0)((a, l) => a + l.count(_ == d)) @@ -50,6 +52,8 @@ object Day08 extends AoC: case Trans case White + given CanEqual[Pix, Pix] = CanEqual.derived + def render: Char = this match case Black => '░' @@ -63,7 +67,7 @@ object Day08 extends AoC: case (_, Trans) => this import Pix.* - + extension (dig: Dig) def digitToPix: Pix = diff --git a/2019/src/main/scala/aoc2019/Day11.scala b/2019/src/main/scala/aoc2019/Day11.scala index cc95c352..abcc2303 100644 --- a/2019/src/main/scala/aoc2019/Day11.scala +++ b/2019/src/main/scala/aoc2019/Day11.scala @@ -1,7 +1,7 @@ package aoc2019 import nmcb.* -import nmcb.pos.* +import nmcb.pos.{*, given} import scala.annotation.tailrec object Day11 extends AoC: diff --git a/2019/src/main/scala/aoc2019/Day13.scala b/2019/src/main/scala/aoc2019/Day13.scala index 9d4d47af..9eae97fa 100644 --- a/2019/src/main/scala/aoc2019/Day13.scala +++ b/2019/src/main/scala/aoc2019/Day13.scala @@ -20,6 +20,8 @@ object Day13 extends AoC: import Tile.* + given CanEqual[Tile, Tile] = CanEqual.derived + case class Location(x: Long, y: Long) extension (outputs: LazyList[Value]) diff --git a/2019/src/main/scala/aoc2019/Day15.scala b/2019/src/main/scala/aoc2019/Day15.scala index 86431375..6f0ff5c4 100644 --- a/2019/src/main/scala/aoc2019/Day15.scala +++ b/2019/src/main/scala/aoc2019/Day15.scala @@ -1,7 +1,7 @@ package aoc2019 import nmcb.* -import nmcb.pos.* +import nmcb.pos.{*, given} import scala.collection.* import scala.collection.immutable.Map diff --git a/2019/src/main/scala/aoc2019/Day17.scala b/2019/src/main/scala/aoc2019/Day17.scala index 922a5429..b86d7bdc 100644 --- a/2019/src/main/scala/aoc2019/Day17.scala +++ b/2019/src/main/scala/aoc2019/Day17.scala @@ -1,7 +1,7 @@ package aoc2019 import nmcb.* -import nmcb.pos.* +import nmcb.pos.{*, given} object Day17 extends AoC: diff --git a/2019/src/main/scala/aoc2019/Day18.scala b/2019/src/main/scala/aoc2019/Day18.scala index 1ea0a3ed..f9660e06 100644 --- a/2019/src/main/scala/aoc2019/Day18.scala +++ b/2019/src/main/scala/aoc2019/Day18.scala @@ -1,7 +1,7 @@ package aoc2019 import nmcb.* -import nmcb.pos.* +import nmcb.pos.{*, given} object Day18 extends AoC: diff --git a/2019/src/main/scala/aoc2019/Day20.scala b/2019/src/main/scala/aoc2019/Day20.scala index 93ab1b70..e5316a46 100644 --- a/2019/src/main/scala/aoc2019/Day20.scala +++ b/2019/src/main/scala/aoc2019/Day20.scala @@ -1,7 +1,7 @@ package aoc2019 import nmcb.* -import nmcb.pos.* +import nmcb.pos.{*, given} object Day20 extends AoC: @@ -14,6 +14,8 @@ object Day20 extends AoC: case Inner(label: String) import Portal.* + + given CanEqual[Portal, Portal] = CanEqual.derived def portalToPortalRoutes(lines: Seq[String]): Map[Portal,Set[(Portal,Int)]] = def peek(x: Int, y: Int): Char = lines.lift(y).flatMap(_.lift(x)).getOrElse(' ') diff --git a/2020/src/main/scala/aoc2020/Day20.scala b/2020/src/main/scala/aoc2020/Day20.scala index 2b3605d6..b6cdd88b 100644 --- a/2020/src/main/scala/aoc2020/Day20.scala +++ b/2020/src/main/scala/aoc2020/Day20.scala @@ -1,7 +1,7 @@ package aoc2020 import nmcb.* -import nmcb.pos.* +import nmcb.pos.{*, given} import nmcb.predef.* import scala.annotation.tailrec diff --git a/2020/src/main/scala/aoc2020/Day23.scala b/2020/src/main/scala/aoc2020/Day23.scala index def67f5e..7f5e21e0 100644 --- a/2020/src/main/scala/aoc2020/Day23.scala +++ b/2020/src/main/scala/aoc2020/Day23.scala @@ -7,6 +7,8 @@ object Day23 extends AoC: /** a singe linked, updatable list of cups */ case class Cup(value: Int, var next: Cup = null) + + given CanEqual[Cup, Cup] = CanEqual.derived def play(digits: Vector[Int], max: Int): Cup = diff --git a/2021/src/main/scala/aoc2021/Day03.scala b/2021/src/main/scala/aoc2021/Day03.scala index 9b21d56b..f71d1989 100644 --- a/2021/src/main/scala/aoc2021/Day03.scala +++ b/2021/src/main/scala/aoc2021/Day03.scala @@ -37,10 +37,10 @@ object Day03 extends AoC: filter(bits).toInt - lazy val gamma = diagnostics.transpose.map(_.mostCommon).toInt - lazy val epsilon = diagnostics.transpose.map(_.leastCommon).toInt - override lazy val answer1 = gamma * epsilon + lazy val gamma: Int = diagnostics.transpose.map(_.mostCommon).toInt + lazy val epsilon: Int = diagnostics.transpose.map(_.leastCommon).toInt + override lazy val answer1: Int = gamma * epsilon - lazy val oxygenRating = rating(diagnostics, _.mostCommon) - lazy val co2SchrubberRating = rating(diagnostics, _.leastCommon) - override lazy val answer2 = oxygenRating * co2SchrubberRating + lazy val oxygenRating: Int = rating(diagnostics, _.mostCommon) + lazy val co2SchrubberRating: Int = rating(diagnostics, _.leastCommon) + override lazy val answer2: Int = oxygenRating * co2SchrubberRating diff --git a/2021/src/main/scala/aoc2021/Day04.scala b/2021/src/main/scala/aoc2021/Day04.scala index 30bae6b3..7e9b87f2 100644 --- a/2021/src/main/scala/aoc2021/Day04.scala +++ b/2021/src/main/scala/aoc2021/Day04.scala @@ -54,6 +54,8 @@ object Day04 extends AoC: object Board: + + given [A] => CanEqual[Board[A], Board[A]] = CanEqual.derived def empty[A]: Board[A] = Board[A](Vector.empty) @@ -66,6 +68,7 @@ object Day04 extends AoC: @tailrec def playWhoWinsLast[A](draws: Vector[A], game: Vector[Board[A]] = boards): Board[A] = + given CanEqual[A, A] = CanEqual.derived val round = game.map(_.draw(draws.head)) val todo = round.filterNot(_.hasBingo) if todo.nonEmpty then diff --git a/2021/src/main/scala/aoc2021/Day09.scala b/2021/src/main/scala/aoc2021/Day09.scala index 88029ee2..3ca9dda0 100644 --- a/2021/src/main/scala/aoc2021/Day09.scala +++ b/2021/src/main/scala/aoc2021/Day09.scala @@ -1,7 +1,7 @@ package aoc2021 import nmcb.* -import nmcb.pos.* +import nmcb.pos.{*, given} import scala.annotation.tailrec diff --git a/2021/src/main/scala/aoc2021/Day13.scala b/2021/src/main/scala/aoc2021/Day13.scala index 7c46f46b..6378144b 100644 --- a/2021/src/main/scala/aoc2021/Day13.scala +++ b/2021/src/main/scala/aoc2021/Day13.scala @@ -1,7 +1,7 @@ package aoc2021 import nmcb.* -import nmcb.pos.* +import nmcb.pos.{*, given} object Day13 extends AoC: @@ -9,6 +9,8 @@ object Day13 extends AoC: case Ver, Hor import Axis.* + + given CanEqual[Axis, Axis] = CanEqual.derived type Dots = Set[Pos] type Folds = Vector[(Axis, Int)] diff --git a/2021/src/main/scala/aoc2021/Day15.scala b/2021/src/main/scala/aoc2021/Day15.scala index 5568228b..43c90fb7 100644 --- a/2021/src/main/scala/aoc2021/Day15.scala +++ b/2021/src/main/scala/aoc2021/Day15.scala @@ -1,7 +1,7 @@ package aoc2021 import nmcb.* -import nmcb.pos.* +import nmcb.pos.{*, given} import scala.math.Integral.Implicits.infixIntegralOps diff --git a/2021/src/main/scala/aoc2021/Day16.scala b/2021/src/main/scala/aoc2021/Day16.scala index c53c65a5..0b058776 100644 --- a/2021/src/main/scala/aoc2021/Day16.scala +++ b/2021/src/main/scala/aoc2021/Day16.scala @@ -29,6 +29,8 @@ object Day16 extends AoC: case I => "1" import Bit.* + + given CanEqual[Bit, Bit] = CanEqual.derived type Version = Int // 3 lsb type Id = Int // 3 lsb diff --git a/2021/src/main/scala/aoc2021/Day20.scala b/2021/src/main/scala/aoc2021/Day20.scala index 9b9998c2..1f4dd74e 100644 --- a/2021/src/main/scala/aoc2021/Day20.scala +++ b/2021/src/main/scala/aoc2021/Day20.scala @@ -1,7 +1,7 @@ package aoc2021 import nmcb.* -import nmcb.pos.* +import nmcb.pos.{*, given} object Day20 extends AoC: diff --git a/2021/src/main/scala/aoc2021/Day22.scala b/2021/src/main/scala/aoc2021/Day22.scala index e9868565..69db74ab 100644 --- a/2021/src/main/scala/aoc2021/Day22.scala +++ b/2021/src/main/scala/aoc2021/Day22.scala @@ -37,6 +37,7 @@ object Day22 extends AoC: def max(that: Position): Position = Position(x.max(that.x), y.max(that.y), z.max(that.z)) + given CanEqual[Position, Position] = CanEqual.derived case class Cuboid(all: Map[Position,Boolean]): diff --git a/2021/src/main/scala/aoc2021/Day25.scala b/2021/src/main/scala/aoc2021/Day25.scala index 7d96578b..625bc186 100644 --- a/2021/src/main/scala/aoc2021/Day25.scala +++ b/2021/src/main/scala/aoc2021/Day25.scala @@ -1,7 +1,7 @@ package aoc2021 import nmcb.* -import nmcb.pos.* +import nmcb.pos.{*, given} import scala.annotation.tailrec @@ -27,7 +27,8 @@ object Day25 extends AoC: val southTiles = southRemoved ++ southUpdated ++ southMoved copy(tiles = southTiles) - + given CanEqual[Floor, Floor] = CanEqual.derived + val floor: Floor = val sizeX = lines.head.size val sizeY = lines.size diff --git a/2021/src/test/scala/aoc2021/Test2021.scala b/2021/src/test/scala/aoc2021/Test2021.scala index 7b2140a9..a684d491 100644 --- a/2021/src/test/scala/aoc2021/Test2021.scala +++ b/2021/src/test/scala/aoc2021/Test2021.scala @@ -3,6 +3,8 @@ package aoc2021 import org.scalatest.funsuite.AnyFunSuite class Test2021 extends AnyFunSuite: + + given CanEqual[Any, Any] = CanEqual.derived test("Day 1: Sonar Sweep"): assertResult(1602)(Day01.answer1) diff --git a/2022/src/main/scala/aoc2022/Day09.scala b/2022/src/main/scala/aoc2022/Day09.scala index 311a5ccb..cedb4604 100644 --- a/2022/src/main/scala/aoc2022/Day09.scala +++ b/2022/src/main/scala/aoc2022/Day09.scala @@ -11,6 +11,8 @@ object Day09 extends AoC: case L import Direction.* + + given CanEqual[Direction, Direction] = CanEqual.derived case class Position(x: Int, y: Int): @@ -58,6 +60,9 @@ object Day09 extends AoC: alignment(h).foldLeft(this)(_ move _) object Position: + + given CanEqual[Position, Position] = CanEqual.derived + def of(x: Int, y: Int): Position = Position(x,y) case class Command(direction: Direction, steps: Int) diff --git a/2022/src/main/scala/aoc2022/Day10.scala b/2022/src/main/scala/aoc2022/Day10.scala index f89ba427..f791ecd4 100644 --- a/2022/src/main/scala/aoc2022/Day10.scala +++ b/2022/src/main/scala/aoc2022/Day10.scala @@ -9,6 +9,8 @@ object Day10 extends AoC: sealed trait Inst case object Nop extends Inst case class Add(value: Int, steps: Int = 2) extends Inst + + given CanEqual[Inst, Inst] = CanEqual.derived lazy val instructions: Vector[Inst] = lines diff --git a/2022/src/main/scala/aoc2022/Day12.scala b/2022/src/main/scala/aoc2022/Day12.scala index 9c4b1210..1ec52dc2 100644 --- a/2022/src/main/scala/aoc2022/Day12.scala +++ b/2022/src/main/scala/aoc2022/Day12.scala @@ -1,7 +1,7 @@ package aoc2022 import nmcb.* -import nmcb.pos.* +import nmcb.pos.{*, given} object Day12 extends AoC: diff --git a/2022/src/main/scala/aoc2022/Day13.scala b/2022/src/main/scala/aoc2022/Day13.scala index 1691094a..3e87155a 100644 --- a/2022/src/main/scala/aoc2022/Day13.scala +++ b/2022/src/main/scala/aoc2022/Day13.scala @@ -8,6 +8,8 @@ object Day13 extends AoC: enum E: case N(n: Long) case L(l: List[E]) + + given CanEqual[E, E] = CanEqual.derived object E: def L(es: E*): L = L(es.toList) diff --git a/2022/src/main/scala/aoc2022/Day14.scala b/2022/src/main/scala/aoc2022/Day14.scala index f49a272e..f2a70dc2 100644 --- a/2022/src/main/scala/aoc2022/Day14.scala +++ b/2022/src/main/scala/aoc2022/Day14.scala @@ -1,7 +1,7 @@ package aoc2022 import nmcb.* -import nmcb.pos.* +import nmcb.pos.{*, given} import scala.annotation.* @@ -11,6 +11,8 @@ object Day14 extends AoC: case Sand case Air case Rock + + given CanEqual[Tile, Tile] = CanEqual.derived def parseLine(line: String): Vector[Pos] = line.trim diff --git a/2022/src/main/scala/aoc2022/Day15.scala b/2022/src/main/scala/aoc2022/Day15.scala index a6a368d1..3dce2fa2 100644 --- a/2022/src/main/scala/aoc2022/Day15.scala +++ b/2022/src/main/scala/aoc2022/Day15.scala @@ -1,7 +1,7 @@ package aoc2022 import nmcb.* -import nmcb.pos.* +import nmcb.pos.{*, given} object Day15 extends AoC: diff --git a/2022/src/main/scala/aoc2022/Day17.scala b/2022/src/main/scala/aoc2022/Day17.scala index b3a373e4..38728302 100644 --- a/2022/src/main/scala/aoc2022/Day17.scala +++ b/2022/src/main/scala/aoc2022/Day17.scala @@ -1,7 +1,7 @@ package aoc2022 import nmcb.* -import nmcb.pos.* +import nmcb.pos.{*, given} import nmcb.predef.* import scala.annotation.* diff --git a/2022/src/main/scala/aoc2022/Day19.scala b/2022/src/main/scala/aoc2022/Day19.scala index 53c43833..ac20c59c 100644 --- a/2022/src/main/scala/aoc2022/Day19.scala +++ b/2022/src/main/scala/aoc2022/Day19.scala @@ -35,7 +35,12 @@ object Day19 extends AoC: import Material.* + given CanEqual[Material, Material] = CanEqual.derived + + case class Robot(material: Material) + + given CanEqual[Robot, Robot] = CanEqual.derived case class MaterialStash(ore: Int = 0, clay: Int = 0, obsidian: Int = 0, geode: Int = 0) @@ -47,6 +52,8 @@ object Day19 extends AoC: case GeodeRobot import Build.* + + given CanEqual[Build, Build] = CanEqual.derived def buildActions(print: Blueprint, material: MaterialStash, robots: Vector[Robot]): Vector[Build] = import material.* diff --git a/2022/src/main/scala/aoc2022/Day22.scala b/2022/src/main/scala/aoc2022/Day22.scala index d1c15a45..6fd424b9 100644 --- a/2022/src/main/scala/aoc2022/Day22.scala +++ b/2022/src/main/scala/aoc2022/Day22.scala @@ -1,7 +1,7 @@ package aoc2022 import nmcb.* -import nmcb.pos.* +import nmcb.pos.{*, given} object Day22 extends AoC: diff --git a/2022/src/main/scala/aoc2022/Day23.scala b/2022/src/main/scala/aoc2022/Day23.scala index 070df08f..9dd11b44 100644 --- a/2022/src/main/scala/aoc2022/Day23.scala +++ b/2022/src/main/scala/aoc2022/Day23.scala @@ -1,7 +1,7 @@ package aoc2022 import nmcb.* -import nmcb.pos.* +import nmcb.pos.{*, given} import scala.annotation.tailrec diff --git a/2022/src/main/scala/aoc2022/Day24.scala b/2022/src/main/scala/aoc2022/Day24.scala index 3556346f..54d5231c 100644 --- a/2022/src/main/scala/aoc2022/Day24.scala +++ b/2022/src/main/scala/aoc2022/Day24.scala @@ -22,6 +22,8 @@ object Day24 extends AoC: case Left extends Dir(char = Field.LeftChar) case Right extends Dir(char = Field.RightChar) + given CanEqual[Dir, Dir] = CanEqual.derived + type Field[A] = Vector[Vector[A]] object Field: diff --git a/2023/src/main/scala/aoc2023/Day03.scala b/2023/src/main/scala/aoc2023/Day03.scala index 65c8a2d3..37646509 100644 --- a/2023/src/main/scala/aoc2023/Day03.scala +++ b/2023/src/main/scala/aoc2023/Day03.scala @@ -1,7 +1,7 @@ package aoc2023 import nmcb.* -import nmcb.pos.* +import nmcb.pos.{*, given} import scala.annotation.* @@ -67,7 +67,7 @@ object Day03 extends AoC: for (g1, ns1) <- gearsWithAdjacentNumbers (g2, ns2) <- gearsWithAdjacentNumbers - if g1 == g2 && ns1.size == 2 && ns2.size == 2 && ns1 == ns2 + if g1 == g2 && ns1.size == 2 && ns2.size == 2 && (ns1 diff ns2).isEmpty yield ns1 ratios.toVector diff --git a/2023/src/main/scala/aoc2023/Day07.scala b/2023/src/main/scala/aoc2023/Day07.scala index 3b29bb36..45efee7f 100644 --- a/2023/src/main/scala/aoc2023/Day07.scala +++ b/2023/src/main/scala/aoc2023/Day07.scala @@ -21,6 +21,8 @@ object Day07 extends AoC: case FiveOfAKind import Strength.* + + given CanEqual[Strength, Strength] = CanEqual.derived given Ordering[Strength] with diff --git a/2023/src/main/scala/aoc2023/Day10.scala b/2023/src/main/scala/aoc2023/Day10.scala index c98a45df..c4a439c7 100644 --- a/2023/src/main/scala/aoc2023/Day10.scala +++ b/2023/src/main/scala/aoc2023/Day10.scala @@ -1,7 +1,7 @@ package aoc2023 import nmcb.* -import nmcb.pos.* +import nmcb.pos.{*, given} import scala.annotation.tailrec @@ -20,6 +20,8 @@ object Day10 extends AoC: if directions.contains(d.opposite) then directions.find(_ != d.opposite) else None import Tile.* + + given CanEqual[Tile, Tile] = CanEqual.derived object Tile: def fromChar(c: Char): Tile = diff --git a/2023/src/main/scala/aoc2023/Day11.scala b/2023/src/main/scala/aoc2023/Day11.scala index 02ffe5ba..4bd7d440 100644 --- a/2023/src/main/scala/aoc2023/Day11.scala +++ b/2023/src/main/scala/aoc2023/Day11.scala @@ -1,7 +1,7 @@ package aoc2023 import nmcb.* -import nmcb.pos.* +import nmcb.pos.{*, given} object Day11 extends AoC: diff --git a/2023/src/main/scala/aoc2023/Day16.scala b/2023/src/main/scala/aoc2023/Day16.scala index 43b6c35b..4708473d 100644 --- a/2023/src/main/scala/aoc2023/Day16.scala +++ b/2023/src/main/scala/aoc2023/Day16.scala @@ -1,7 +1,7 @@ package aoc2023 import nmcb.* -import nmcb.pos.* +import nmcb.pos.{*, given} import scala.annotation.tailrec diff --git a/2023/src/main/scala/aoc2023/Day17.scala b/2023/src/main/scala/aoc2023/Day17.scala index 9e310a7d..01e3db5c 100644 --- a/2023/src/main/scala/aoc2023/Day17.scala +++ b/2023/src/main/scala/aoc2023/Day17.scala @@ -2,7 +2,7 @@ package aoc2023 import nmcb.* import nmcb.predef.* -import nmcb.pos.* +import nmcb.pos.{*, given} import scala.collection.mutable diff --git a/2023/src/main/scala/aoc2023/Day18.scala b/2023/src/main/scala/aoc2023/Day18.scala index 686f6920..3f56a6e9 100644 --- a/2023/src/main/scala/aoc2023/Day18.scala +++ b/2023/src/main/scala/aoc2023/Day18.scala @@ -1,7 +1,7 @@ package aoc2023 import nmcb.* -import nmcb.pos.* +import nmcb.pos.{*, given} import scala.annotation.tailrec diff --git a/2023/src/main/scala/aoc2023/Day19.scala b/2023/src/main/scala/aoc2023/Day19.scala index 5cc14daa..12880d9d 100644 --- a/2023/src/main/scala/aoc2023/Day19.scala +++ b/2023/src/main/scala/aoc2023/Day19.scala @@ -15,6 +15,8 @@ object Day19 extends AoC: case Compared(select1: Part => Boolean, select2: Long => Boolean, workflow: String, selector: Char) import Rule.* + + given CanEqual[Rule, Rule] = CanEqual.derived case class Range(from: Long, to: Long): def size: Long = to - from + 1 diff --git a/2023/src/main/scala/aoc2023/Day20.scala b/2023/src/main/scala/aoc2023/Day20.scala index 6342036d..9913e56f 100644 --- a/2023/src/main/scala/aoc2023/Day20.scala +++ b/2023/src/main/scala/aoc2023/Day20.scala @@ -11,6 +11,8 @@ object Day20 extends AoC: case L import Pulse.* + + given CanEqual[Pulse, Pulse] = CanEqual.derived type Name = String type Message = (Name, Name, Pulse) diff --git a/2023/src/main/scala/aoc2023/Day21.scala b/2023/src/main/scala/aoc2023/Day21.scala index 442a043e..0caae601 100644 --- a/2023/src/main/scala/aoc2023/Day21.scala +++ b/2023/src/main/scala/aoc2023/Day21.scala @@ -1,7 +1,7 @@ package aoc2023 import nmcb.* -import nmcb.pos.* +import nmcb.pos.{*, given} import scala.annotation.tailrec diff --git a/2023/src/main/scala/aoc2023/Day22.scala b/2023/src/main/scala/aoc2023/Day22.scala index b078d943..321603a1 100644 --- a/2023/src/main/scala/aoc2023/Day22.scala +++ b/2023/src/main/scala/aoc2023/Day22.scala @@ -95,6 +95,8 @@ object Day22 extends AoC: intersect(that).isDefined object Box: + + given CanEqual[Box, Box] = CanEqual.derived def fromString(s: String): Box = s match diff --git a/2023/src/main/scala/aoc2023/Day23.scala b/2023/src/main/scala/aoc2023/Day23.scala index 16382d8e..d02c3beb 100644 --- a/2023/src/main/scala/aoc2023/Day23.scala +++ b/2023/src/main/scala/aoc2023/Day23.scala @@ -1,7 +1,7 @@ package aoc2023 import nmcb.* -import nmcb.pos.* +import nmcb.pos.{*, given} import scala.collection.mutable diff --git a/2024/src/main/scala/aoc2024/Day04.scala b/2024/src/main/scala/aoc2024/Day04.scala index d2bf292c..12f2eb74 100644 --- a/2024/src/main/scala/aoc2024/Day04.scala +++ b/2024/src/main/scala/aoc2024/Day04.scala @@ -1,7 +1,7 @@ package aoc2024 import nmcb.* -import pos.* +import pos.{*, given} object Day04 extends AoC: diff --git a/2024/src/main/scala/aoc2024/Day06.scala b/2024/src/main/scala/aoc2024/Day06.scala index 5d5b13b8..39f72310 100644 --- a/2024/src/main/scala/aoc2024/Day06.scala +++ b/2024/src/main/scala/aoc2024/Day06.scala @@ -1,7 +1,7 @@ package aoc2024 import nmcb.* -import pos.* +import pos.{*, given} import scala.annotation.* diff --git a/2024/src/main/scala/aoc2024/Day08.scala b/2024/src/main/scala/aoc2024/Day08.scala index 7883cd90..af05308a 100644 --- a/2024/src/main/scala/aoc2024/Day08.scala +++ b/2024/src/main/scala/aoc2024/Day08.scala @@ -1,7 +1,7 @@ package aoc2024 import nmcb.* -import pos.* +import pos.{*, given} import nmcb.predef.* object Day08 extends AoC: diff --git a/2024/src/main/scala/aoc2024/Day09.scala b/2024/src/main/scala/aoc2024/Day09.scala index 2580ebbb..6c06f94d 100644 --- a/2024/src/main/scala/aoc2024/Day09.scala +++ b/2024/src/main/scala/aoc2024/Day09.scala @@ -7,8 +7,8 @@ import scala.annotation.* object Day09 extends AoC: case class Block(id: Int): - def isFileBlock: Boolean = this != Block.free - def isFreeBlock: Boolean = this == Block.free + def isFileBlock: Boolean = this.id != Block.free.id + def isFreeBlock: Boolean = this.id == Block.free.id def asString: String = if id == -1 then "." else id.toString object Block: diff --git a/2024/src/main/scala/aoc2024/Day10.scala b/2024/src/main/scala/aoc2024/Day10.scala index 6d3067bc..9eef080e 100644 --- a/2024/src/main/scala/aoc2024/Day10.scala +++ b/2024/src/main/scala/aoc2024/Day10.scala @@ -1,7 +1,7 @@ package aoc2024 import nmcb.* -import nmcb.pos.* +import nmcb.pos.{*, given} object Day10 extends AoC: diff --git a/2024/src/main/scala/aoc2024/Day12.scala b/2024/src/main/scala/aoc2024/Day12.scala index 0d771b62..2c31d6b0 100644 --- a/2024/src/main/scala/aoc2024/Day12.scala +++ b/2024/src/main/scala/aoc2024/Day12.scala @@ -2,7 +2,7 @@ package aoc2024 import nmcb.* import nmcb.predef.* -import nmcb.pos.* +import nmcb.pos.{*, given} import scala.annotation.* diff --git a/2024/src/main/scala/aoc2024/Day14.scala b/2024/src/main/scala/aoc2024/Day14.scala index 7cae0e7d..16e5e42c 100644 --- a/2024/src/main/scala/aoc2024/Day14.scala +++ b/2024/src/main/scala/aoc2024/Day14.scala @@ -1,7 +1,7 @@ package aoc2024 import nmcb.* -import nmcb.pos.* +import nmcb.pos.{*, given} import scala.annotation.* diff --git a/2024/src/main/scala/aoc2024/Day15.scala b/2024/src/main/scala/aoc2024/Day15.scala index e5d346b6..8169b051 100644 --- a/2024/src/main/scala/aoc2024/Day15.scala +++ b/2024/src/main/scala/aoc2024/Day15.scala @@ -1,7 +1,7 @@ package aoc2024 import nmcb.* -import nmcb.pos.* +import nmcb.pos.{*, given} import scala.annotation.* diff --git a/2024/src/main/scala/aoc2024/Day16.scala b/2024/src/main/scala/aoc2024/Day16.scala index 3d1b8042..4a566419 100644 --- a/2024/src/main/scala/aoc2024/Day16.scala +++ b/2024/src/main/scala/aoc2024/Day16.scala @@ -1,7 +1,7 @@ package aoc2024 import nmcb.* -import nmcb.pos.* +import nmcb.pos.{*, given} import nmcb.predef.* object Day16 extends AoC: diff --git a/2024/src/main/scala/aoc2024/Day18.scala b/2024/src/main/scala/aoc2024/Day18.scala index c6fbef1f..750a9344 100644 --- a/2024/src/main/scala/aoc2024/Day18.scala +++ b/2024/src/main/scala/aoc2024/Day18.scala @@ -1,7 +1,7 @@ package aoc2024 import nmcb.* -import nmcb.pos.* +import nmcb.pos.{*, given} import scala.annotation.* diff --git a/2024/src/main/scala/aoc2024/Day20.scala b/2024/src/main/scala/aoc2024/Day20.scala index 04cab1eb..290edd71 100644 --- a/2024/src/main/scala/aoc2024/Day20.scala +++ b/2024/src/main/scala/aoc2024/Day20.scala @@ -1,7 +1,7 @@ package aoc2024 import nmcb.* -import nmcb.pos.* +import nmcb.pos.{*, given} import scala.Option.* import scala.annotation.* diff --git a/2024/src/main/scala/aoc2024/Day21.scala b/2024/src/main/scala/aoc2024/Day21.scala index cd3df4b0..d01ea835 100644 --- a/2024/src/main/scala/aoc2024/Day21.scala +++ b/2024/src/main/scala/aoc2024/Day21.scala @@ -1,7 +1,7 @@ package aoc2024 import nmcb.* -import nmcb.pos.* +import nmcb.pos.{*, given} import nmcb.predef.* import scala.collection.immutable.Map diff --git a/2024/src/test/scala/aoc2024/Test2024.scala b/2024/src/test/scala/aoc2024/Test2024.scala index 5f520b48..8f51ca88 100644 --- a/2024/src/test/scala/aoc2024/Test2024.scala +++ b/2024/src/test/scala/aoc2024/Test2024.scala @@ -1,6 +1,6 @@ package aoc2024 -import nmcb.pos.* +import nmcb.pos.{*, given} import org.scalatest.funsuite.AnyFunSuite diff --git a/2025/src/main/scala/aoc2025/Day10.scala b/2025/src/main/scala/aoc2025/Day10.scala index af560299..2a24f0f9 100644 --- a/2025/src/main/scala/aoc2025/Day10.scala +++ b/2025/src/main/scala/aoc2025/Day10.scala @@ -3,6 +3,7 @@ package aoc2025 import nmcb.* import nmcb.predef.* +import scala.CanEqual.derived import scala.annotation.* object Day10 extends AoC: @@ -82,7 +83,6 @@ object Day10 extends AoC: import scala.jdk.CollectionConverters.* val ctx = new Context(Map("model" -> "true").asJava) - import ctx.* // (3) (1,3) (2) (2,3) (0,2) (0,1) {3,5,4,7} // @@ -97,33 +97,35 @@ object Day10 extends AoC: // x0 = 1, x1 = 3, x2 = 3, x4 = 1, x5 = 2 - val optimizer = mkOptimize() + val optimizer = ctx.mkOptimize() /** defines variables x0, x1, ... xn */ val xs: Vector[IntExpr] = buttons .zipWithIndex - .map((_,i) => mkIntConst(s"x$i")) + .map((_,i) => ctx.mkIntConst(s"x$i")) /** add constraints x0 >= 0, x1 >= 0 ... xn >= 0 */ for presses <- xs do - optimizer.Add(mkGe(presses, mkInt(0))) + optimizer.Add(ctx.mkGe(presses, ctx.mkInt(0))) /** add goal minimise for x0 + x1 + ... xn */ val total: ArithExpr[IntSort] = - xs.foldLeft[ArithExpr[IntSort]](mkInt(0)): (x,y) => - mkAdd(x,y) + xs.foldLeft[ArithExpr[IntSort]](ctx.mkInt(0)): (x,y) => + ctx.mkAdd(x,y) optimizer.MkMinimize(total) /** joltage(i) - b(i0) - b(i1) - b(in) = 0 */ - (buttons zip xs) - .foldLeft(joltages.map[ArithExpr[IntSort]](mkInt)): + buttons + .zip(xs) + .foldLeft(joltages.map[ArithExpr[IntSort]](ctx.mkInt)): case (expressions, (b, x)) => b.indices.foldLeft(expressions): (expressions, i) => - expressions.updated(i, mkSub(expressions(i), x)) + expressions.updated(i, ctx.mkSub(expressions(i), x)) .foreach: joltageLeft => - optimizer.Add(mkEq(joltageLeft, mkInt(0))) + optimizer.Add(ctx.mkEq(joltageLeft, ctx.mkInt(0))) + given CanEqual[Status, Status] = CanEqual.derived assert(optimizer.Check() == Status.SATISFIABLE) optimizer.getModel.evaluate(total, false).toString.toInt diff --git a/build.sbt b/build.sbt index 8fd925f0..26a258bc 100644 --- a/build.sbt +++ b/build.sbt @@ -20,6 +20,7 @@ ThisBuild / scalacOptions ++= Seq( "-feature", "-language:implicitConversions", "-language:existentials", + "-language:strictEquality", "-unchecked", "-Werror", "-deprecation" diff --git a/nmcb/src/main/scala/nmcb/AoC.scala b/nmcb/src/main/scala/nmcb/AoC.scala index 3442600e..09c1a6fb 100644 --- a/nmcb/src/main/scala/nmcb/AoC.scala +++ b/nmcb/src/main/scala/nmcb/AoC.scala @@ -30,5 +30,5 @@ abstract class AoC: println(s"Answer $day part 1: $answer1 [${System.currentTimeMillis - start1}ms]") val start2: Long = System.currentTimeMillis - if answer2 != "" then + if answer2.toString != "" then println(s"Answer $day part 2: $answer2 [${System.currentTimeMillis - start2}ms]") diff --git a/nmcb/src/main/scala/nmcb/Dijkstra.scala b/nmcb/src/main/scala/nmcb/Dijkstra.scala index ebd03f9a..88caf45e 100644 --- a/nmcb/src/main/scala/nmcb/Dijkstra.scala +++ b/nmcb/src/main/scala/nmcb/Dijkstra.scala @@ -1,6 +1,6 @@ package nmcb -import pos.* +import pos.{*, given} import predef.* import scala.annotation.* @@ -30,7 +30,7 @@ object Dijkstra: def fromEdges[A](edges: Vector[Edge[A]]): Graph[A] = Graph(edges.groupMap(_.from)(identity)) - def fromGrid[A](grid: Grid[A], node: A, dist: (Pos,Pos) => Int = (_,_) => 1): Graph[Pos] = + def fromGrid[A](grid: Grid[A], node: A, dist: (Pos,Pos) => Int = (_,_) => 1)(using CanEqual[A, A]): Graph[Pos] = grid.elements .filter(_.element == node) .foldLeft(Graph.empty): (graph,from) => @@ -61,7 +61,7 @@ object Dijkstra: import scala.collection.mutable /** classic dijkstra traverses the shortest found paths first */ - def run[A](from: A, graph: A => Set[(A,Int)]): Result[A] = + def run[A](from: A, graph: A => Set[(A,Int)])(using CanEqual[A, A]): Result[A] = val edgeTo: mutable.Map[A,Edge[A]] = mutable.Map.empty val distTo: mutable.Map[A,Int] = mutable.Map.empty.withDefaultValue(Int.MaxValue) @@ -82,7 +82,7 @@ object Dijkstra: Result(edgeTo.toMap, distTo.toMap) /** classic dijkstra traverses the shortest found paths first */ - def run[A](from: A, graph: Graph[A]): Result[A] = + def run[A](from: A, graph: Graph[A])(using CanEqual[A, A]): Result[A] = val edgeTo: mutable.Map[A, Edge[A]] = mutable.Map.empty val distTo: mutable.Map[A, Int] = mutable.Map.from(graph.neighbours.map((node, _) => node -> Int.MaxValue)).withDefaultValue(Int.MaxValue) diff --git a/nmcb/src/main/scala/nmcb/Grid.scala b/nmcb/src/main/scala/nmcb/Grid.scala index 6473cef9..759e88f5 100644 --- a/nmcb/src/main/scala/nmcb/Grid.scala +++ b/nmcb/src/main/scala/nmcb/Grid.scala @@ -1,7 +1,7 @@ package nmcb import Dijkstra.* -import pos.* +import pos.{*, given} case class Grid[+A](matrix: Vector[Vector[A]]): val sizeY: Int = matrix.size @@ -32,13 +32,13 @@ case class Grid[+A](matrix: Vector[Vector[A]]): def peekOrElse[A1 >: A](p: Pos, default: => A1): A1 = peekOption(p).getOrElse(default) - def find[A1 >: A](a: A1): Option[Pos] = + def find[A1 >: A](a: A1)(using CanEqual[A, A1]): Option[Pos] = elements.find(_.element == a).map(_.pos) - def findAll[A1 >: A](a: A1): Set[Pos] = + def findAll[A1 >: A](a: A1)(using CanEqual[A, A1]): Set[Pos] = elements.filter(_.element == a).map(_.pos) - def findOne[A1 >: A](a: A1, default: => Pos = sys.error(s"not found")): Pos = + def findOne[A1 >: A](a: A1, default: => Pos = sys.error(s"not found"))(using CanEqual[A, A1]): Pos = find(a).getOrElse(default) def filter[A1 >: A](f: ((Pos,A1)) => Boolean): Set[(Pos,A1)] = @@ -59,7 +59,7 @@ case class Grid[+A](matrix: Vector[Vector[A]]): def asString: String = matrix.map(_.mkString("")).mkString("\n") - def extractPath[A1 >: A](from: A1, to: A1, node: A1): (Pos,Pos,Grid[A1]) = + def extractPath[A1 >: A](from: A1, to: A1, node: A1)(using CanEqual[A, A1]): (Pos,Pos,Grid[A1]) = val fromPos = findOne(from) val toPos = findOne(to) val cleared = updated(fromPos, node).updated(toPos, node) @@ -113,8 +113,10 @@ object Grid: def to: Pos = g._2 def cleared: Grid[A] = g._3 - def shortest: Vector[Pos] = + def shortest: Vector[Pos] = { + given CanEqual[A, A] = CanEqual.derived Dijkstra .run(from, Graph.fromGrid(cleared, cleared.peek(from))) .pathTo(to) .toTrail + } diff --git a/nmcb/src/main/scala/nmcb/pos.scala b/nmcb/src/main/scala/nmcb/pos.scala index dcac9b31..f3192ef1 100644 --- a/nmcb/src/main/scala/nmcb/pos.scala +++ b/nmcb/src/main/scala/nmcb/pos.scala @@ -1,5 +1,7 @@ package nmcb +import scala.CanEqual.derived + object pos: enum Dir: @@ -26,12 +28,16 @@ object pos: case E => W case W => E - export Dir.* + export Dir.{*, given} type Pos = (x: Int, y: Int) given Ordering[Pos] = Ordering.by(_.toTuple) + given CanEqual[Pos, Pos] = CanEqual.derived + + given CanEqual[Dir, Dir] = CanEqual.derived + object Pos: @@ -111,7 +117,7 @@ object pos: def adjoint8: Set[Pos] = Pos.offset8.map(_ + p) - infix inline def step(dir: Dir): Pos = + infix inline def step(dir: Dir)(using CanEqual[Dir, Dir]): Pos = dir match case N => (x = p.x, y = p.y - 1) case E => (x = p.x + 1, y = p.y) diff --git a/nmcb/src/test/scala/nmcb/TestDijkstra.scala b/nmcb/src/test/scala/nmcb/TestDijkstra.scala index baa1513b..4e673c90 100644 --- a/nmcb/src/test/scala/nmcb/TestDijkstra.scala +++ b/nmcb/src/test/scala/nmcb/TestDijkstra.scala @@ -1,7 +1,7 @@ package nmcb import nmcb.* -import pos.* +import pos.{*, given} import nmcb.Dijkstra.* import nmcb.predef.* import org.scalatest.funsuite.AnyFunSuite