Powered by AppSignal & Oban Pro

Day 2: Rock Paper Scissors

2022/day_02.livemd

Day 2: Rock Paper Scissors

Mix.install([:kino])

input = Kino.Input.textarea("Please paste your input:")

Part 1

Run in Livebook

https://adventofcode.com/2022/day/2

data =
  input
  |> Kino.Input.read()
  |> String.split("\n")
  |> Enum.reject(&(&1 == ""))
  |> Enum.map(&(&1 |> String.split(" ")))
calc_shape_score = fn
  "X" -> 1
  "Y" -> 2
  "Z" -> 3
end

get_outcome = fn
  "A", "X" -> :draw
  "A", "Y" -> :won
  "A", "Z" -> :lost
  "B", "X" -> :lost
  "B", "Y" -> :draw
  "B", "Z" -> :won
  "C", "X" -> :won
  "C", "Y" -> :lost
  "C", "Z" -> :draw
end

calc_outcome_score = fn
  :lost -> 0
  :draw -> 3
  :won -> 6
end

calc_score = fn opponent_shape, player_shape ->
  calc_shape_score.(player_shape) +
    calc_outcome_score.(get_outcome.(opponent_shape, player_shape))
end

_answer1 =
  data
  |> Enum.map(fn [opponent_shape, player_shape] -> calc_score.(opponent_shape, player_shape) end)
  |> Enum.sum()

Part 2

https://adventofcode.com/2022/day/2#part2

trans_outcome = fn
  "X" -> :lost
  "Y" -> :draw
  "Z" -> :won
end

get_player_shape = fn
  "A", :lost -> "Z"
  "A", :draw -> "X"
  "A", :won -> "Y"
  "B", :lost -> "X"
  "B", :draw -> "Y"
  "B", :won -> "Z"
  "C", :lost -> "Y"
  "C", :won -> "X"
  "C", :draw -> "Z"
end

calc_score = fn opponent_shape, raw_outcome ->
  outcome = trans_outcome.(raw_outcome)
  player_shape = get_player_shape.(opponent_shape, outcome)

  calc_shape_score.(player_shape) + calc_outcome_score.(outcome)
end

_answer2 =
  data
  |> Enum.map(fn [opponent_shape, raw_outcome] -> calc_score.(opponent_shape, raw_outcome) end)
  |> Enum.sum()

Better Solution

# Record result set
results = [
  {:rock, :rock, :draw},
  {:rock, :paper, :won},
  {:rock, :scissors, :lost},
  {:paper, :rock, :lost},
  {:paper, :paper, :draw},
  {:paper, :scissors, :won},
  {:scissors, :rock, :won},
  {:scissors, :paper, :lost},
  {:scissors, :scissors, :draw}
]

decode = fn
  input when input in ["A", "X"] -> :rock
  input when input in ["B", "Y"] -> :paper
  input when input in ["C", "Z"] -> :scissors
end

calc_shape_score = fn
  :rock -> 1
  :paper -> 2
  :scissors -> 3
end

calc_outcome_score = fn
  :lost -> 0
  :draw -> 3
  :won -> 6
end

# Part 1

get_outcome = fn opponent_shape, player_shape ->
  results
  |> Enum.find_value(fn
    {^opponent_shape, ^player_shape, outcome} -> outcome
    _ -> nil
  end)
end

calc_score = fn raw_opponent_shape, raw_player_shape ->
  opponent_shape = decode.(raw_opponent_shape)
  player_shape = decode.(raw_player_shape)

  calc_shape_score.(player_shape) +
    calc_outcome_score.(get_outcome.(opponent_shape, player_shape))
end

answer1 =
  data
  |> Enum.map(fn [raw_opponent_shape, raw_player_shape] ->
    calc_score.(raw_opponent_shape, raw_player_shape)
  end)
  |> Enum.sum()

# Part 2

trans_outcome = fn
  "X" -> :lost
  "Y" -> :draw
  "Z" -> :won
end

get_player_shape = fn opponent_shape, outcome ->
  results
  |> Enum.find_value(fn
    {^opponent_shape, player_shape, ^outcome} -> player_shape
    _ -> nil
  end)
end

calc_score = fn raw_opponent_shape, raw_outcome ->
  opponent_shape = decode.(raw_opponent_shape)
  outcome = trans_outcome.(raw_outcome)

  player_shape = get_player_shape.(opponent_shape, outcome)

  calc_shape_score.(player_shape) + calc_outcome_score.(outcome)
end

answer2 =
  data
  |> Enum.map(fn [raw_opponent_shape, raw_outcome] ->
    calc_score.(raw_opponent_shape, raw_outcome)
  end)
  |> Enum.sum()

{answer1, answer2}