Advent of Code (2016) : Day 5

-- 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.Day5 do

  def md5_hex(input_string) do
    :crypto.hash(:md5, input_string) |> Base.encode16
  end

  def generate_password_1(door_id) do
    do_generate_password_1(door_id, 0, [])
  end

  def do_generate_password_1(_, _, result) when length(result) == 8 do
    Enum.reverse(result)
  end

  def do_generate_password_1(door_id, index, result) do
    input_string = door_id <> Integer.to_string(index)
    case md5_hex(input_string) do
      "00000" <> rest -> do_generate_password_1(door_id, index + 1, [String.at(rest, 0) | result])
      _ -> do_generate_password_1(door_id, index + 1, result)
    end
  end

  def output_1() do
    generate_password_1("ffykfhsq")
  end

  def generate_password_2(door_id) do
    do_generate_password_2(door_id, 0, ["0","1","2","3","4","5","6","7"], [])
  end

  def do_generate_password_2(_, _, [], result) do
    IO.puts("Decryption complete")
    IO.write("Password is -- ")
    Enum.sort(result)
    |> Enum.map_join(fn({_,char}) -> char end)
  end

  def do_generate_password_2(door_id, index, position_list, result) do
    input_string = door_id <> Integer.to_string(index)
    << trailing_zeros::40 >> <> << position, password_char >> <> _rest = md5_hex(input_string)
    case {<< trailing_zeros::40 >>, << position >> in position_list} do
      {"00000", true} ->
        IO.puts("Decryption progress -- #{((length(result) + 1) / 8) * 100}% done")
        do_generate_password_2(door_id, index + 1, position_list -- [<< position >>], [{<< position >>, << password_char >>} | result])
      _ -> do_generate_password_2(door_id, index + 1, position_list, result)
    end
  end

  def output_2() do
    generate_password_2("ffykfhsq")
  end

end

    

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