Skip to content

Instantly share code, notes, and snippets.

@dcbriccetti
Last active December 18, 2020 06:27
Show Gist options
  • Save dcbriccetti/f59bccadf2513816bc566e93bd653567 to your computer and use it in GitHub Desktop.
Save dcbriccetti/f59bccadf2513816bc566e93bd653567 to your computer and use it in GitHub Desktop.
package com.davebsoft
import scala.collection.mutable
import scala.io.Source
import scala.util.Using
case class FieldRanges(line: String) {
private val re = "([\\w ]+): (\\d+)-(\\d+) or (\\d+)-(\\d+)".r
private val m = re.findFirstMatchIn(line).get
val name: String = m.group(1)
val ranges = Seq(
Range.inclusive(m.group(2).toInt, m.group(3).toInt),
Range.inclusive(m.group(4).toInt, m.group(5).toInt))
def inRange(number: Int): Boolean = ranges.exists(_.contains(number))
}
object Day16 extends App {
val data: String = Using(Source.fromFile("src/main/resources/day16.txt")) {_.mkString}.get
val sections: Array[String] = data.split("\n\n")
val ranges: Seq[Range.Inclusive] = "(\\d+)-(\\d+)".r.findAllMatchIn(sections(0)).map { m =>
Range.inclusive(m.group(1).toInt, m.group(2).toInt)
}.toSeq
println(part1)
println(part2)
private def part1: Int = {
val numbers: Iterator[Int] = "(\\d+)".r.findAllMatchIn(sections(2)).map(_.group(1).toInt)
val badNumbers = numbers.filter { number => !ranges.exists {_.contains(number)} }
badNumbers.sum
}
def part2: Long = {
val fieldRanges: Seq[FieldRanges] = sections(0).split("\n").map(FieldRanges).toSeq
val myTicketNums = sections(1).split("\n").drop(1)(0).split(",").map(_.toInt)
val nearbyTickets: Seq[Seq[Int]] = sections(2).split("\n").drop(1).toSeq.map {
_.split(",").map(_.toInt).toSeq
}
val goodNearbyTickets: Seq[Seq[Int]] = nearbyTickets.filter {
_.forall { num => ranges.exists {_.contains(num)}}}
val potentialTicketFields: Seq[Seq[Seq[FieldRanges]]] =
goodNearbyTickets.map { numbers: Seq[Int] =>
numbers.map {number => fieldRanges.filter(_.inRange(number))}
}
val ticket0Fields = potentialTicketFields.head
val intersectedFields: IndexedSeq[mutable.Set[String]] = for {
fieldIndex <- ticket0Fields.indices
fieldIntersections: mutable.Set[FieldRanges] = potentialTicketFields.foldLeft(ticket0Fields(fieldIndex).to(mutable.Set)) {
(acc: mutable.Set[FieldRanges], v: Seq[Seq[FieldRanges]]) => acc.intersect(v(fieldIndex).toSet)}
} yield fieldIntersections.map(_.name)
println(intersectedFields)
var done = false
while (! done) {
var unresolved = false
val knownFieldNames: Seq[Option[String]] = intersectedFields.map {
fieldNames: mutable.Set[String] => if (fieldNames.size == 1) Some(fieldNames.toSeq.head) else None }
knownFieldNames.zipWithIndex.filter { _._1.nonEmpty }.foreach { nameAndIndex =>
intersectedFields.zipWithIndex.foreach { setOfNamesAndIndex =>
if (setOfNamesAndIndex._2 != nameAndIndex._2) {
setOfNamesAndIndex._1 -= nameAndIndex._1.get // Remove the known name from other positions
if (setOfNamesAndIndex._1.size > 1) unresolved = true
}
}
}
if (! unresolved) done = true
}
val fieldNames: Seq[String] = intersectedFields.map(_.toSeq.head)
val departureFieldsAndValues: Seq[(Int, String)] =
myTicketNums.zip(fieldNames).filter { numAndName: (Int, String) =>
numAndName._2.startsWith("departure")
}.toSeq
println(departureFieldsAndValues)
departureFieldsAndValues.map(_._1.toLong).product
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment