Advent of Code (2016) : Day 2

-- Problem --
You can find Part 1 of the problem statement here. Part 2 is unlocked on successful completion of Part 1.

-- Solution in Elixir --

      defmodule Aoc.Day2 do

  @input "RRLLDDRLLDURLDUUDULDLRLDDDRLDULLRDDRDLUUDLLRRDURRLUDUDULLUUDRUURRDDDDURUULLDULRLRRRDLLLRDLRDULDLRUUDRURLULURUUDRLUUDRDURUUDDDRDLLRDLUDRLUUUUUULDURDRDDURLDDRLUUDLRURRDRLDRDLRRRLURULDLUUURDRLUULRDUDLDRRRDDLDDDRLRLLDRDUURDULUURRRRUDLLUDLDRLLRRULLLRDRDRRDRDRDUULUDLULRLLDRULURLURDLLDDRRLUDRDUULLDRULLLRLULUDDLURLUULDRUDRLDUUDDLLLRURDRLDRLUUUUUUDRUDLDLULULRRURRDDDUDRRRDDDLDDLRLLDDUULLUDRURDDDRDDLURRURULULUUDRLLUUDDDRUULRDLDLLRUUDRRLRRRULLRRURUDDUUDULDUDUUUDURUDUUDUDRULUDULRDUDUUUUDLLURDLRRUDURDDUULLDLLRDUDULRLRDURLRDRDLRDLRURUDURLULDDDLDRLULLRLURRLLDLRLLULLDUURUUDRULDDUDLDDR
LUURULURUURRRDLRDRDDDUDULRDDLUUDUUULRLRRLRUDDLDLURLRULUUDUUDLDRLLUURLUUURDUDLUULLUUDUUDRDUDUDURLLURDUDLDLDDLDUDRLLUULDDRUDDDRLRUDRDUDULLRRDLLDDLRLLLRLRURURLLDULUDDUULULDRRLUURDULRULUDULDULDULRULLLRRDRLDRLDUULLDDULRLUDLLLULDDLULLUULUURRULDLUULDRRUDDDLRDLULDULDRRDLRRRLRUDURUDDDUDDURRRLDUULRDDLRRRLRUULDDURDRDUULDLLULULDRDRUULDLULRUUDUDLUDRLRDURRRRLULURDRLLLUDRRRDRURRLRLLUURDLURLURDULURUDDULLDUUDDLRLUULRDUUDRDRUDRLUUUDURLLRDRRDRURDDDDULLDDUDLDUUDLRLURURLDRRDRDUDLRRDRUDRDLURRLLLULULULRUDDDULULULDDRRLULUUUURDDURURLDLDDDDDRULUUUULLUDDDRRLUULDUULRUUDUURRLLRDDRUURL
RRRLLLLUULLRRLLDRULULLLRDLLDLDDLURUDLULUULLRURLDULLUDULDRURDURLULLDUDDRLLRUURDLLULUURLULLDLRRDDDULUURRUDRDRDURULDLLURUDLLLDDUDLLLLRLDRDRDDRRDLUUDLLLULLLLLDDRDLULLLLRURRRUUUULLDLRDLDLRRRULRRRRLDLLRDURULDDLURURUULULDRDDDURLRDDRDULLUURUDUUUDRDRRLURULULRLUUDDRDULDRLULULUULRLDRLUDRRDDDRUDDRDDRDDRRLRDLRURDULULRRUUURDRRRDURDDRUDULUUDRDDLDRDDDULDLRDUULDUULRUDLRRDDDLLDDLLLRRDLDUULUULULURRULLRRUDUDRUDRRRLDLRLURRLUDLLLUUDDUDRURUUDDURDURULRLDUDRDLULDUDRUDDDR
DRDRRUUUUURRLUDLDLRUUULRLDLRRRDDUDLUUDUDDLRDUDLRRLLURUUDULLUDLULLDLLDDULUDDUDUULURLDLDDUUDDRDDRLUURLUUDUDUDURULLDRLDDRUDLURRRLDRLRULDDLDDLDDDULDUDDLLDULUUDUDDUULDRLDRLRURDULUDDRRLRRLRRDULDRRDUDUDRLDURRLRLRDLRLRRLRDDDRULLULULDUDDLDLULRLLURRRRULUULRUDLDLRDLLURURUUURDRRRLDDRLRLURDDURDDUURUUUDDLRUURRRDLLUULUDRLDDRDDDDUUDRLRRDULDULRDLLLRULULLRDRULLRDLRUUURRRURLRRDLDRDDLURLDLULLDUURRDULUUURRLLDDUUUULDDDDLRDDDRDLDLLUURLDDRULUDDRDDDLRDU
DRRRLURUDUDUULDLLURLUUDDRRRDUDLURLLDRRLLDDURULUDUURURULLRLDLLUURDLLDLLDLDLRUDLLLLDRLLUDLLDULDDRRURDRRLRLRRUURRUDURRLDRDLDURUULUDRLLURLUDURDULLRLLDLURLRRDLLLLUUDRDULLDLURDULDRDURRRLDRLURULULURLLLRRRUULRLRRDRDDDLULRLRRDLUDDUUUUUDRRDLDUDUURLDRRRLRUDRULDRLURUULRDLDDLRURDLURULRRLDURLDUURURULRDUDRRUDUDDLRLUURURULDDLULULULDULRRLRRURUURLRLLDRRLUDLUURDRRURRUUDULRLURRLRLRDDRURDDLRRDUDRLLUUUDULRDRULUURRLRLRDUDULDRDLLUDRDLLDRULDLUUURDDRDDUDDULLLDRRDDUDDDDLDDRLRULRRRURRDRULLDDDURDDLURRDDDUDLURRUDUDLLDDDLRUUDRLRRLRDUUUDDL"

  # given an initial button and a list of instructions
  # find the final button by reducing the list of instructions
  # using the provided reducer function
  def decode_helper(instruction_list, init_button, reducer) do
    Enum.reduce(instruction_list, init_button, reducer)
  end

  # given a list of instruction lists and a reducer function
  # which is used as an argument for decode_helper
  # take the initial button as 5 and find the final button for each instruction list
  # this list of final buttons has to be reversed to find the code
  def decode(input_list, reducer) do
    Enum.reduce(input_list,{[], 5}, fn(list, {partial_code, curr_button}) ->
      new_button = decode_helper(list, curr_button, reducer)
      {[new_button | partial_code], new_button}
    end)
    |> elem(0) |> Enum.reverse()
  end

  # get the next button given the current button
  # and a single instruction
  # use this as reducer for part-1
  def next_button_1(instruction, button) do
    case {instruction, button} do
      {"U", num} when num in 1..3 -> num
      {"U", num} -> num - 3
      {"D", num} when num in 7..9 -> num
      {"D", num} -> num + 3
      {"L", num} when num in [1,4,7] -> num
      {"L", num} -> num - 1
      {"R", num} when num in [3,6,9] -> num
      {"R", num} -> num + 1
    end
  end

  # get the next button given the current button
  # and a single instruction
  # representing A,B,C,D by 10,11,12,13 respectively, for convenience
  # use this as reducer for part-2
  def next_button_2(instruction, button) do
    case {instruction, button} do
      {"U", num} when num in [1,2,4,5,9] -> num
      {"U", num} when num in [6,7,8,10,11,12] -> num - 4
      {"U", num} when num in [3,13] -> num - 2
      {"D", num} when num in [5,9,10,12,13] -> num
      {"D", num} when num in [2,3,4,6,7,8] -> num + 4
      {"D", num} when num in [1,11] -> num + 2
      {"R", num} when num in [1,4,9,12,13] -> num
      {"R", num} -> num + 1
      {"L", num} when num in [1,2,5,10,13] -> num
      {"L", num} -> num - 1
    end
  end

  def parse_input(input_string) do
    String.split(input_string)
    |> Enum.map(&String.graphemes/1)
  end

  # output for part-1
  def output_1() do
    parse_input(@input)
    |> decode(&next_button_1/2)
  end

  # output for part-2
  # also need to convert 10,11,12,13 to "A","B","C","D"
  # that is done by <> as ?A is 65
  def output_2() do
    parse_input(@input)
    |> decode(&next_button_2/2)
    |> Enum.map(fn(x) ->
      cond do
        x in [10,11,12,13] -> <>
        true -> x
      end
    end)
  end

end

    

You can find all my Advent of Code (2016) solutions here.