-
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
-
Used some stacks for day 18. Got lazy and added padding around the braces so everything had a space between it and the next element:
https://gist.github.com/dmckennell/94848a751dd8385a3f9e61bff82adefe
-
Day 15 (missed a few days and don't think I'll have time/energy to trawl back): https://gist.github.com/dmckennell/b55a51f8e018792d94381d46cc081c0f
Not the most optimal:
Part 1: 639 Part 2: 266 final map size: 3611963 took 17.286220559 seconds
-
Day 11 (was not as short as I hoped): https://gist.github.com/dmckennell/dff4c6aec6f4d3c5597cea219e964954
-
-
Sadly no -
collectFirst
takes a partial function (in this casePartialFunction[(Instruction, Int), Int]
) which I can't wrangle theinput
collection into. It's a bit of a 'square peg round hole' situation. I should probably craft something myself for such a case.In your code snippet the case would be satisfied on the first instruction and I would then get a
NoSuchElementException
. -
Not the most elegant, but we got there: https://gist.github.com/dmckennell/45bc2e70e2990e43e262ffbcee95f67f
Couldn't avoid running the program a second time in part 2 when I discover the program is completing successfully following a swap. Would like to have memoized the program result used in my if condition, but not seeing an easy way to manage that with
collectFirst
. -
Squeezed in a small amount of time to get today's finished (using Scala again):
https://gist.github.com/dmckennell/6645ad73208043f403481e780ae49ea2
...didn't read the second part too much and just plumped for some logic which seems to work -
Day 4 done with regex mainly.
https://gist.github.com/dmckennell/f8b44c1d6c15dbdff05480d2360b8c9e
...generates:
Part 1 took 0.085530307 seconds Part 2 took 0.050166096 seconds Part 1: 213 Part 2: 147
-
After some classic idiocy around leaving some checks in my input file, I created this:
https://gist.github.com/dmckennell/0c9ad748facfb350944e9cb41915039e...and got:
Part 1 took 0.012765501 seconds Part 2 took 0.002681801 seconds Part 1: 153 Part 2: 2421944712
-
Not this year (as I want to focus on just getting to the end of the advent this time), but I'd like to see your solutions as you go as I'm curious!
Have seen a few GitHub projects with some Haskell advent GitHub projects with file reading scaffolding in place, so will likely clone one of those before next year's challenge.
-
Was a quick one today.
https://gist.github.com/dmckennell/bcb6db60d0150bfc877b21492d4f0f78
...prints:
Solving puzzle for Day 2 (Year 2020) Loading input from 2020/Day02.txt Part 1 took 0.030277581 seconds Part 2 took 0.021179534 seconds Part 1: 528 Part 2: 497
-
Using a Scala app with the following snippet
https://gist.github.com/dmckennell/aca20ed0ee112be4806ea0ca7bb09038gets me
Solving puzzle for Day 1 (Year 2020) Loading input from 2020/Day01.txt Part 1 took 0.176238641 seconds Part 2 took 0.15863768 seconds Part 1: 926464 Part 2: 65656536
-
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.