I’m using this starter kit for the scaffolding so I can simply run mix test for the example and mix d01.p2 to run the solution for my specific data set.

I’ve got the following code that passes p1 completely and the p2 example but not my specific data set. I can’t find any bugs but the result fails for being “too high” and I’m really not sure why this is not being accepted. I have the debug output for each step and running through it manually everything seems right to me.

Is anyone able to point me in the right direction on what I’m missing?

https://pastebin.com/US8ikNLx
defmodule AdventOfCode.Day01 do
  def part1(args) do
    args
    |> String.split(~r/\n/, trim: true)
    |> Enum.map(&line_calibration_value/1)
    |> Enum.sum()
  end

  def part2(args) do
    args
    |> String.split(~r/\n/, trim: true)
    |> Enum.map(&words_to_numbers/1)
    |> Enum.map(&line_calibration_value/1)
    |> Enum.sum()
  end

  defp words_to_numbers(string) do
    numbers = ["one", "two", "three", "four", "five", "six", "seven", "eight", "nine"]

    String.replace(string, numbers, fn x ->
      (Enum.find_index(numbers, &(&1 == x)) + 1)
      |> Integer.to_string()
    end)
  end

  # TODO: doesn't work if the string has no numbers
  defp line_calibration_value(string) do
    # remove any non-numeric characters
    number_from_string = String.replace(string, ~r/[^\d]/, "")

    calibration_number = [
      # first number
      String.at(number_from_string, 0),
      # last number, or first number is string has length of 1
      String.at(number_from_string, -1)
    ]

    calibration_number
    |> List.to_string()
    |> String.to_integer()
  end
end
  • sjmulder@lemmy.sdf.org
    link
    fedilink
    arrow-up
    8
    ·
    11 months ago

    I haven’t studied your code but mine stumbled over this input line at one point:

    eightjzqzhrllg1oneightfck

    Simpler test:

    12 oneight

    Should yield 18 for part 2.

    • stifle867@programming.devOP
      link
      fedilink
      arrow-up
      3
      ·
      11 months ago

      Thank you for the test case! I went out for dinner but I’ll work on this tomorrow. I strongly suspect this is the exact issue but I’m going to have to rework some things so I want to tackle it with a fresh mind.

  • anonymouse@sh.itjust.works
    link
    fedilink
    arrow-up
    6
    ·
    11 months ago

    I think it’s related to the replacement of words with digits. There are some overlapping words, for example in “eightwothree” the “t” is used for both “eighT” and “Two”. In this case the order of replacement differs your result. It either becomes “8wo3” or “eigh23”.

    • stifle867@programming.devOP
      link
      fedilink
      arrow-up
      2
      ·
      11 months ago

      I think you may be right but the problem is at the end of the string. I’ll add some test cases and rewrite the code. I think I’ll have to ditch the regex replacements and scan through instead so I don’t clobber the string in the wrong place.

  • Cyno@programming.dev
    link
    fedilink
    arrow-up
    1
    ·
    11 months ago

    Do share if you find the input that was causing trouble, I’m tripping on some miniscule error as well and i have no idea what could it be

    • stifle867@programming.devOP
      link
      fedilink
      arrow-up
      2
      ·
      11 months ago

      I just added this to my test case and when it passed the solution also passed:

      assert part2("12oneightfve") === 18

      • Cyno@programming.dev
        link
        fedilink
        arrow-up
        1
        ·
        11 months ago

        Thanks, I managed to find the culprit in the end however - I was using a forward-look of 5 characters for finding if it matches a word so in a string of a3two for example, it would register the two before the 3. It was an easy fix once i found the issue.

  • stifle867@programming.devOP
    link
    fedilink
    arrow-up
    1
    ·
    11 months ago

    I arrived at the following solution for Day #1:

    https://pastebin.com/u1SYJ4tY
    defmodule AdventOfCode.Day01 do
      def part1(args) do
        number_regex = ~r/([0-9])/
    
        args
        |> String.split(~r/\n/, trim: true)
        |> Enum.map(&first_and_last_number(&1, number_regex))
        |> Enum.map(&number_list_to_integer/1)
        |> Enum.sum()
      end
    
      def part2(args) do
        number_regex = ~r/(?=(one|two|three|four|five|six|seven|eight|nine|[0-9]))/
    
        args
        |> String.split(~r/\n/, trim: true)
        |> Enum.map(&first_and_last_number(&1, number_regex))
        |> Enum.map(fn number -> Enum.map(number, &replace_word_with_number/1) end)
        |> Enum.map(&number_list_to_integer/1)
        |> Enum.sum()
      end
    
      defp first_and_last_number(string, regex) do
        matches = Regex.scan(regex, string)
        [_, first] = List.first(matches)
        [_, last] = List.last(matches)
    
        [first, last]
      end
    
      defp number_list_to_integer(list) do
        list
        |> List.to_string()
        |> String.to_integer()
      end
    
      defp replace_word_with_number(string) do
        numbers = ["one", "two", "three", "four", "five", "six", "seven", "eight", "nine"]
    
        String.replace(string, numbers, fn x ->
          (Enum.find_index(numbers, &(&1 == x)) + 1)
          |> Integer.to_string()
        end)
      end
    end