Most recent activity
-
Didn't use sets here, but enjoying reading the other approaches with that technique.
def findFirstMarker(input: String, distinctCount: Int): Int = @tailrec def markerIndexAtEndOfUniqueCharSequence(buffer: Array[Char], idx: Int = 0): Int = val current = input(idx) if (buffer.size == (distinctCount - 1) && !buffer.contains(current)) idx else val (_, prunedBuffer) = buffer.splitAt(buffer.indexOf(current) + 1) markerIndexAtEndOfUniqueCharSequence(prunedBuffer :+ current, idx + 1) markerIndexAtEndOfUniqueCharSequence(Array.emptyCharArray, 0) + 1
-
Also seeing what people use as their measure of "done".
Agreed - that's what I'm often most interested in when viewing how others approach the problem.
If my immediate approach to getting the answer is suboptimal - especially when compared to other clean, but efficient methods written by others - then I'll make a mental note of that better approach and take it with me to the next problem. I've found from previous years that if I'm too caught up in worrying about writing 'imperfect' solutions then I'll not get anything done, so I figure at least getting something which is not horrifically slow should suffice.
I figured I'd do a little bit of input modification for today's solution so that I didn't spend more than a few minutes on some regex which would invariably fail:
Lesson learned from today is to always verify my output from parsing before moving on to writing the solver. Was a right pain when I realised my initial parsing approach resulted in a shifted crate.
Day 5 solution (tried keeping this hidden/collapsible but well formatted and failing):
"Day 5" - { enum CraneMoverModel: case `9000`, `9001` case class Instruction(from: Int, to: Int, number: Int) val crateRegex = """\[([A-Z-])\]""".r val instructionRegex = """^move\s(\d+)\sfrom\s(\d+)\sto\s(\d+)$""".r def gatherInstructions(instructionsInput: String): Array[Instruction] = instructionsInput.split("\\n").map { case instructionRegex(number, from, to) => Instruction(from.toInt, to.toInt, number.toInt) } def gatherCrates(cratesInput: String): Map[Int, Array[Char]] = cratesInput.split("\\n") .map: crate => crateRegex.findAllMatchIn(crate).map(_.group(1)).toArray .transpose .map: crates => crates .reverse .filterNot(_ == "-") // input blank crates have been changed to hyphens for convenience .map(_.charAt(0)) .zipWithIndex.map { (crateArray, idx) => (idx + 1, crateArray) }.toMap /* Following modifications made to input: - stack number line removed - empty crates have been relabelled as [-] */ def parseInput(input: String): (Array[Instruction], Map[Int, Array[Char]]) = val Array(crateInfo, instructionInfo) = input.split("\\n\\n") (gatherInstructions(instructionInfo), gatherCrates(crateInfo)) def solve(input: String, craneMoverModel: CraneMoverModel): String = val (instructions, cratesMap) = parseInput(input) val result = instructions.foldLeft(cratesMap) { (currentCrates, instruction) => val from = currentCrates(instruction.from) val to = currentCrates(instruction.to) val valuesToAdd = from.takeRight(instruction.number) val add = craneMoverModel match case CraneMoverModel.`9000` => valuesToAdd.reverse case CraneMoverModel.`9001` => valuesToAdd currentCrates .updated(instruction.from, from.dropRight(instruction.number)) .updated(instruction.to, to ++: add) } result .toArray .sortBy: (idx, _) => idx .flatMap: (_, crates) => crates.lastOption .mkString "sample part a" in: inputStringFor(Day.`5`, Input.sample, Part.a).use: input => IO.println(solve(input, CraneMoverModel.`9000`)) "part a" in : inputStringFor(Day.`5`, Input.real, Part.a).use: input => IO.println(solve(input, CraneMoverModel.`9000`)) "sample part b" in: inputStringFor(Day.`5`, Input.sample, Part.b).use: input => IO.println(solve(input, CraneMoverModel.`9001`)) "part b" in : inputStringFor(Day.`5`, Input.real, Part.b).use: input => IO.println(solve(input, CraneMoverModel.`9001`)) }
-
Back to solving using Scala as it's the language I'm most comfortable with. Only using versions 2.12.* and 2.13.* in work projects, so it's nice to try the new version 3 features (particularly those relating to syntax). Making use of a test framework to run/split up scenarios rather than writing scripts/apps for each day so that I have everything just in one file and don't faff.
Got that usual feeling of a false sense of security when completing the last few days in a short space of time. Will hopefully have the willpower to keep going when things start taking more than 30 minutes to solve.
Day 4:
"Day 4" - { case class Section(begin: Int, end: Int) def getElfPairs(assignmentInput: String): (Section, Section) = assignmentInput.split(",") match case Array(first, second) => val Array(beginFirst, endFirst) = first.split("-") val Array(beginSecond, endSecond) = second.split("-") (Section(beginFirst.toInt, endFirst.toInt), Section(beginSecond.toInt, endSecond.toInt)) object PartA: def sectionContainsOther(thisSection: Section, thatSection: Section): Boolean = (thisSection.begin <= thatSection.begin && thisSection.end >= thatSection.end) || (thatSection.begin <= thisSection.begin && thatSection.end >= thisSection.end) object PartB: def sectionOverlapsOther(thisSection: Section, thatSection: Section): Boolean = !((thisSection.end < thatSection.begin) || (thatSection.end < thisSection.begin)) "sample part a" in: linesFor(Day.`4`, Input.sample, Part.a).use: lines => IO.println(lines.map(getElfPairs).filter(PartA.sectionContainsOther).size) "part a" in: linesFor(Day.`4`, Input.real, Part.a).use: lines => IO.println(lines.map(getElfPairs).filter(PartA.sectionContainsOther).size) "sample part b" in: linesFor(Day.`4`, Input.sample, Part.b).use: lines => IO.println(lines.map(getElfPairs).filter(PartB.sectionOverlapsOther).size) "part b" in: linesFor(Day.`4`, Input.real, Part.b).use: lines => IO.println(lines.map(getElfPairs).filter(PartB.sectionOverlapsOther).size) }
-
-
-
I do enjoy the cases where I just have to change a parameter value to get part 2.
frequencies
anditerate
in the standard lib made it a bit easier to model.https://gist.github.com/dmckennell/d9a52000647c7ed59cd63873579c6f91
-
Today's part 2 was quite easy to anticipate.
https://gist.github.com/dmckennell/a1ecf3f1366c7feabad19051eb521c3b -
Day 2 done without too much pain once I got familiar with techniques for parsing the input.
https://gist.github.com/dmckennell/86ac3155367122502be2643f4b021edfNice to see such a broad range of languages this year. Enjoying reading through and understanding the approaches of others.
-
Have decided to at least start in Clojure this year. Will fall back to Scala if needed.
Completely new to Clojure, so will be tracking other solutions online after I've completed each day to see how I can improve. Here's the gist of day 1: https://gist.github.com/dmckennell/21aeee2c44ff52a868e69f5d6c17ccb7
Definitely had a case of rushing into things with today's problem and ended up paying the price with debugging part 2, which took some hours in total if I'm honest.