Last active
December 18, 2020 06:27
-
-
Save dcbriccetti/f59bccadf2513816bc566e93bd653567 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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