mirror of
https://github.com/mx42/aoc2024.scala.git
synced 2026-01-14 05:49:51 +01:00
feat: basic wrapper + days 1 to 3
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -32,3 +32,5 @@ metals.sbt
|
|||||||
/.worksheet/
|
/.worksheet/
|
||||||
|
|
||||||
.direnv
|
.direnv
|
||||||
|
|
||||||
|
src/main/resources
|
||||||
|
|||||||
2
.scalafmt.conf
Normal file
2
.scalafmt.conf
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
version = "3.7.15"
|
||||||
|
runner.dialect = scala3
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
## sbt project compiled with Scala 3
|
## Advent of Code 2024
|
||||||
|
|
||||||
### Usage
|
### Usage
|
||||||
|
|
||||||
This is a normal sbt project. You can compile code with `sbt compile`, run it with `sbt run`, and `sbt console` will start a Scala 3 REPL.
|
- Put input in `src/main/resources/days/dayXX.txt`
|
||||||
|
- Run SBT `sbt`
|
||||||
|
- In SBT shell, run day: `run XX`
|
||||||
|
|
||||||
For more information on the sbt-dotty plugin, see the
|
|
||||||
[scala3-example-project](https://github.com/scala/scala3-example-project/blob/main/README.md).
|
|
||||||
|
|||||||
@@ -5,8 +5,7 @@ lazy val root = project
|
|||||||
.settings(
|
.settings(
|
||||||
name := "AOC2024",
|
name := "AOC2024",
|
||||||
version := "0.1.0-SNAPSHOT",
|
version := "0.1.0-SNAPSHOT",
|
||||||
|
|
||||||
scalaVersion := scala3Version,
|
scalaVersion := scala3Version,
|
||||||
|
fork := true,
|
||||||
libraryDependencies += "org.scalameta" %% "munit" % "1.0.0" % Test
|
libraryDependencies += "org.scalameta" %% "munit" % "1.0.0" % Test
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,5 +1,10 @@
|
|||||||
@main def hello(): Unit =
|
import days._
|
||||||
println("Hello world!")
|
|
||||||
println(msg)
|
|
||||||
|
|
||||||
def msg = "I was compiled by Scala 3. :)"
|
@main def main(dayNumber: Int): Unit = {
|
||||||
|
dayNumber match {
|
||||||
|
case 1 => Day1.solve()
|
||||||
|
case 2 => Day2.solve()
|
||||||
|
case 3 => Day3.solve()
|
||||||
|
case _ => println(s"Day $dayNumber is not yet implemented.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
31
src/main/scala/days/Day.scala
Normal file
31
src/main/scala/days/Day.scala
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
package days
|
||||||
|
|
||||||
|
import scala.io.Source
|
||||||
|
|
||||||
|
trait Day {
|
||||||
|
val number: Int
|
||||||
|
|
||||||
|
def getInput(): Option[String] = {
|
||||||
|
val resourcePath = getClass.getResource(s"day${number}.txt")
|
||||||
|
if (resourcePath != null) {
|
||||||
|
Some(Source.fromURL(resourcePath).mkString)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def solve(): Unit = {
|
||||||
|
getInput() match {
|
||||||
|
case Some(input) => {
|
||||||
|
println(s"Day: $number")
|
||||||
|
println(s"Part 1: ${part1(input)}")
|
||||||
|
println(s"Part 2: ${part2(input)}")
|
||||||
|
}
|
||||||
|
case None =>
|
||||||
|
println(s"Missing day $number input")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def part1(input: String): String
|
||||||
|
def part2(input: String): String
|
||||||
|
}
|
||||||
35
src/main/scala/days/Day1.scala
Normal file
35
src/main/scala/days/Day1.scala
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
package days
|
||||||
|
|
||||||
|
object Day1 extends Day {
|
||||||
|
val number: Int = 1;
|
||||||
|
|
||||||
|
def inputToLists(input: String): (List[Int], List[Int]) =
|
||||||
|
input.linesIterator
|
||||||
|
.map(l => {
|
||||||
|
val line = l.split(" ")
|
||||||
|
(line(0).toInt, line.last.toInt)
|
||||||
|
})
|
||||||
|
.foldLeft((Nil, Nil): Tuple2[List[Int], List[Int]]) {
|
||||||
|
case ((accL, accR), (l, r)) => (l :: accL, r :: accR)
|
||||||
|
}
|
||||||
|
|
||||||
|
def part1(input: String) = {
|
||||||
|
val (leftList, rightList) = inputToLists(input)
|
||||||
|
leftList
|
||||||
|
.sorted()
|
||||||
|
.zip(rightList.sorted())
|
||||||
|
.map((a, b) => (a - b).abs)
|
||||||
|
.sum
|
||||||
|
.toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
def part2(input: String) = {
|
||||||
|
val (leftList, rightList) = inputToLists(input)
|
||||||
|
val counts =
|
||||||
|
rightList.sorted
|
||||||
|
.groupBy((n: Int) => n)
|
||||||
|
.mapValues(_.length)
|
||||||
|
|
||||||
|
leftList.map(n => counts.getOrElse(n, 0) * n).sum().toString()
|
||||||
|
}
|
||||||
|
}
|
||||||
56
src/main/scala/days/Day2.scala
Normal file
56
src/main/scala/days/Day2.scala
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
package days
|
||||||
|
|
||||||
|
object Day2 extends Day {
|
||||||
|
val number: Int = 2;
|
||||||
|
|
||||||
|
def checkFnP1(input: List[Int], order: Option[Boolean]): Boolean =
|
||||||
|
input match {
|
||||||
|
case Nil => true
|
||||||
|
case _ :: Nil => true
|
||||||
|
case a :: b :: t => {
|
||||||
|
val diff = a - b
|
||||||
|
if (diff < -3 || diff > 3 || diff == 0) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
val curOrder = Some(diff > 0)
|
||||||
|
val newOrder: Option[Boolean] = (order, curOrder) match {
|
||||||
|
case (None, a) => a
|
||||||
|
case (a, b) if a == b => a
|
||||||
|
case _ => return false
|
||||||
|
}
|
||||||
|
checkFnP1(b :: t, newOrder)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def checkFnP2(
|
||||||
|
input: List[Int]
|
||||||
|
): Boolean = {
|
||||||
|
// Wanted to try a recursive approach like p1 but I gave up.. :(
|
||||||
|
if (checkFnP1(input, None)) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
(0 until (input.length)).iterator
|
||||||
|
.map { n =>
|
||||||
|
{
|
||||||
|
val (before, after) = input.splitAt(n)
|
||||||
|
val newInput = before ++ after.tail
|
||||||
|
checkFnP1(newInput, None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.dropWhile(_ == false)
|
||||||
|
.nextOption
|
||||||
|
.getOrElse(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
def part1(input: String) =
|
||||||
|
input.linesIterator
|
||||||
|
.map(s => checkFnP1(s.split(" ").map(_.toInt).toList, None))
|
||||||
|
.count(_ == true)
|
||||||
|
.toString()
|
||||||
|
|
||||||
|
def part2(input: String) =
|
||||||
|
input.linesIterator
|
||||||
|
.map(s => checkFnP2(s.split(" ").map(_.toInt).toList))
|
||||||
|
.count(_ == true)
|
||||||
|
.toString()
|
||||||
|
}
|
||||||
32
src/main/scala/days/Day3.scala
Normal file
32
src/main/scala/days/Day3.scala
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
package days
|
||||||
|
|
||||||
|
import scala.util.matching.Regex
|
||||||
|
|
||||||
|
object Day3 extends Day {
|
||||||
|
val number: Int = 3;
|
||||||
|
|
||||||
|
def part1(input: String) =
|
||||||
|
"mul\\(([0-9]+),([0-9]+)\\)".r
|
||||||
|
.findAllMatchIn(input)
|
||||||
|
.map(m => m.group(1).toInt * m.group(2).toInt)
|
||||||
|
.sum()
|
||||||
|
.toString()
|
||||||
|
|
||||||
|
def part2(input: String) =
|
||||||
|
"(do)\\(\\)|(don't)\\(\\)|mul\\(([0-9]+),([0-9]+)\\)".r
|
||||||
|
.findAllMatchIn(input)
|
||||||
|
.foldLeft((true, 0)) {
|
||||||
|
// Activate flag if "do()" matched
|
||||||
|
case ((_, acc), m) if m.group(1) != null => (true, acc)
|
||||||
|
// Deactivate flag if "dont() matched"
|
||||||
|
case ((_, acc), m) if m.group(2) != null => (false, acc)
|
||||||
|
// Ignore mul() if deactivated
|
||||||
|
case ((false, acc), _) => (false, acc)
|
||||||
|
// Add mul() result to the accumulator
|
||||||
|
case ((true, acc), m) =>
|
||||||
|
(true, acc + m.group(3).toInt * m.group(4).toInt)
|
||||||
|
}
|
||||||
|
._2
|
||||||
|
.toString()
|
||||||
|
|
||||||
|
}
|
||||||
9
src/main/scala/days/Day4.scala
Normal file
9
src/main/scala/days/Day4.scala
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
package days
|
||||||
|
|
||||||
|
object Day4 extends Day {
|
||||||
|
val number: Int = 4;
|
||||||
|
|
||||||
|
def part1(input: String) = "pouet"
|
||||||
|
|
||||||
|
def part2(input: String) = "pouet"
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user