Avatar for DavidM_

DavidM_

Member since Feb 2018 • Last active Dec 2024
  • 4 conversations
  • 116 comments

Most recent activity

  • Avatar for DavidM_

    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.

  • Avatar for DavidM_

    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
    
  • Avatar for DavidM_

    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`))  
    
      }
    
  • Avatar for DavidM_

    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)
      }
    
  • in Miscellaneous and Meaningless
    Avatar for DavidM_

    Scattergories?

    edit: probably not exactly what you’re looking for as it doesn’t incorporate this sort of betting element.

  • in Complete bikes and frame & forks
    Avatar for DavidM_

    Stunning bike! Would have snapped it up if I was still based in the UK :(

    GLWS!

  • Avatar for DavidM_

    I do enjoy the cases where I just have to change a parameter value to get part 2.
    frequencies and iterate in the standard lib made it a bit easier to model.

    https://gist.github.com/dmckennell/d9a52000647c7ed59cd63873579c6f91

  • Avatar for DavidM_

    Day 2 done without too much pain once I got familiar with techniques for parsing the input.
    https://gist.github.com/dmckennell/86ac3155367122502be2643f4b021edf

    Nice to see such a broad range of languages this year. Enjoying reading through and understanding the approaches of others.

  • Avatar for DavidM_

    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

Actions