Crab Combat
defmodule Aoc2020.Day22 do
@moduledoc "Crab Combat"
def run() do
part_2()
end
def part_1() do
[player1, player2] = parse_input()
play_combat(player1, player2)
|> calculate_score()
end
def part_2() do
decks = parse_input()
IO.puts("Starting game")
play_recursive(decks, [])
|> Enum.find(fn deck -> length(deck) > 0 end)
|> calculate_score()
end
def parse_input() do
File.read!("priv/inputs/2020/day22.txt")
# test_input()
|> String.trim()
|> String.split("\n\n")
|> Enum.map(&parse_deck/1)
end
def test_input() do
"Player 1:\n9\n2\n6\n3\n1\n\nPlayer 2:\n5\n8\n4\n7\n10"
end
def loop_test() do
"Player 1:\n43\n19\n\nPlayer 2:\n2\n29\n14"
end
def parse_deck(str) do
str
|> String.split("\n")
|> tl()
|> Enum.map(&String.to_integer/1)
end
def play_combat(p1_deck, []), do: p1_deck
def play_combat([], p2_deck), do: p2_deck
def play_combat([p1_card | p1_deck], [p2_card | p2_deck]) when p1_card > p2_card do
play_combat(p1_deck ++ [p1_card, p2_card], p2_deck)
end
def play_combat([p1_card | p1_deck], [p2_card | p2_deck]) when p2_card > p1_card do
play_combat(p1_deck, p2_deck ++ [p2_card, p1_card])
end
def play_recursive([player1, _] = decks, history, game \\ 1) do
IO.inspect(game: game, turn: length(history) + 1)
if Enum.member?(history, decks) do
[player1, []]
else
case decks do
[p1_deck, []] ->
[p1_deck, []]
[[], p2_deck] ->
[[], p2_deck]
[[p1_card | p1_deck], [p2_card | p2_deck]]
when p1_card <= length(p1_deck) and p2_card <= length(p2_deck) ->
case play_recursive([p1_deck, p2_deck], [decks | history], game + 1) do
[_, []] ->
play_recursive([p1_deck ++ [p1_card, p2_card], p2_deck], [decks | history], game)
[[], _] ->
play_recursive([p1_deck, p2_deck ++ [p2_card, p1_card]], [decks | history], game)
end
[[p1_card | p1_deck], [p2_card | p2_deck]] when p1_card > p2_card ->
play_recursive([p1_deck ++ [p1_card, p2_card], p2_deck], [decks | history], game)
[[p1_card | p1_deck], [p2_card | p2_deck]] when p2_card > p1_card ->
play_recursive([p1_deck, p2_deck ++ [p2_card, p1_card]], [decks | history], game)
end
end
end
def calculate_score(deck) do
Enum.reverse(deck)
|> Enum.with_index()
|> Enum.map(fn {v, index} -> v * (index + 1) end)
|> Enum.sum()
end
end