Skip to content

Latest commit

 

History

History
1093 lines (869 loc) · 45.8 KB

aoc2022.livemd

File metadata and controls

1093 lines (869 loc) · 45.8 KB

AOC2022

Mix.install([
  {:ex_parameterized, "~> 1.3"}
])
Resolving Hex dependencies...
Dependency resolution completed:
New:
  ex_parameterized 1.3.7
* Getting ex_parameterized (Hex package)
==> ex_parameterized
Compiling 3 files (.ex)
Generated ex_parameterized app
:ok

Day1

defmodule Day1 do
  def read_data(data) do
    data
    |> String.split("\n\n")
    |> Enum.map(fn sublist ->
      sublist
      |> String.split()
      |> Enum.map(&String.to_integer(&1))
    end)
  end

  def puzzle1(data) do
    data
    |> Enum.map(&Enum.sum(&1))
    |> Enum.max()
  end

  def puzzle2(data) do
    data
    |> Enum.map(&Enum.sum(&1))
    |> Enum.sort(:desc)
    |> Enum.take(3)
    |> Enum.sum()
  end
end
{:module, Day1, <<70, 79, 82, 49, 0, 0, 9, ...>>, {:puzzle2, 1}}
ExUnit.start(auto_run: false)

defmodule Day1Test do
  use ExUnit.Case, async: false

  setup_all do
    {:ok,
     data: """
     1000
     2000
     3000

     4000

     5000
     6000

     7000
     8000
     9000

     10000
     """}
  end

  describe "Day1" do
    test "test data", state do
      assert state[:data]
             |> Day1.read_data()
             |> length == 5
    end

    test "test max calories", state do
      assert state[:data]
             |> Day1.read_data()
             |> Day1.puzzle1() == 24000
    end

    test "top 3 calories", state do
      assert state[:data]
             |> Day1.read_data()
             |> Day1.puzzle2() == 45000
    end
  end
end
{:module, Day1Test, <<70, 79, 82, 49, 0, 0, 18, ...>>, {:"test Day1 top 3 calories", 1}}
ExUnit.run()
...
Finished in 0.01 seconds (0.00s async, 0.01s sync)
3 tests, 0 failures

Randomized with seed 627574
%{excluded: 0, failures: 0, skipped: 0, total: 3}
day1_input = File.read!("/Users/akode/dev/advent_of_code/aoc2022/day1.txt")
"18814\n\n1927\n12782\n8734\n10904\n9548\n1493\n\n4576\n4235\n2617\n1012\n2088\n1325\n1249\n5173\n4893\n3295\n2376\n2714\n6210\n\n6684\n5766\n3442\n4901\n4875\n4815\n5898\n2410\n5789\n4133\n3590\n1342\n\n8867\n7109\n2904\n5810\n3254\n4257\n2508\n3580\n5494\n\n11885\n14638\n11891\n4244\n\n11603\n17113\n\n8341\n2993\n7759\n7219\n2962\n8020\n6176\n6100\n6168\n5467\n\n8884\n11521\n3912\n2993\n13471\n\n3093\n4064\n9130\n7665\n10440\n6175\n7390\n10297\n\n29896\n7553\n\n3709\n5876\n3564\n3824\n7695\n6789\n4295\n1603\n2170\n1004\n7871\n\n5020\n1414\n2741\n6719\n2845\n6136\n6399\n1252\n3594\n5522\n7969\n\n5693\n2115\n11763\n9283\n12287\n\n7006\n5946\n10795\n1196\n7918\n5157\n7856\n\n4240\n2887\n11614\n5791\n11635\n3458\n11730\n\n4843\n8330\n7046\n\n6100\n4280\n5609\n6975\n3704\n3033\n4953\n8469\n4844\n6110\n\n12946\n25227\n10688\n\n2403\n1851\n2695\n3953\n5878\n2712\n2516\n5473\n3877\n1955\n5663\n1627\n2777\n3082\n\n56364\n\n4636\n6558\n2535\n3165\n2685\n4797\n6021\n5666\n4233\n1469\n7070\n\n7209\n2433\n7902\n3515\n5477\n9505\n5126\n9294\n4364\n\n8355\n\n2434\n1139\n2011\n3784\n1194\n2270\n6072\n5157\n3428\n3915\n2201\n1769\n3530\n4034\n3381\n\n1032\n6856\n6760\n5918\n5255\n\n37294\n\n5331\n8102\n3359\n3692\n6645\n10076\n8602\n2726\n\n1196\n3789\n9127\n15026\n10039\n\n44620\n\n33181\n\n7325\n5261\n\n6633\n1629\n13650\n13046\n9180\n13952\n\n8267\n4591\n7888\n5919\n3255\n3938\n5320\n6318\n1016\n5467\n\n4945\n4766\n4089\n6270\n5951\n3624\n1294\n2845\n6236\n2284\n6016\n6171\n2888\n3417\n\n7105\n3162\n5163\n6685\n5034\n5590\n3857\n1349\n3110\n3216\n5713\n4128\n\n3345\n5178\n2139\n6009\n3656\n3985\n2925\n1878\n5277\n2548\n5014\n4170\n2068\n5406\n3782\n\n4545\n3019\n4971\n5443\n4041\n2992\n2572\n1746\n6324\n2505\n4059\n4559\n3282\n6281\n\n2479\n1227\n1920\n1652\n7127\n5330\n5773\n7980\n5979\n1327\n6926\n\n5533\n4924\n4501\n1595\n5068\n1872\n1756\n6565\n4526\n2686\n1905\n4323\n4340\n\n6740\n9667\n7552\n1838\n4250\n8439\n2018\n9334\n4571\n\n5685\n2107\n3006\n1731\n2252\n2543\n4018\n6351\n1533\n5665\n2671\n2983\n\n7982\n5914\n7895\n1973\n6270\n1546\n1333\n6630\n7107\n5563\n1223\n\n3377\n1575\n6806\n6269\n5158\n5195\n2001\n1896\n8137\n\n4449\n2044\n1954\n4646\n4853\n2901\n4696\n3729\n2467\n5396\n1370\n5768\n3729\n1122\n2760\n\n5594\n3736\n4226\n5677\n1451\n5936\n3771\n1747\n4692\n1991\n3244\n5235\n2494\n1136\n2600\n\n60004\n\n10268\n7786\n8060\n10508\n5528\n6774\n\n1428\n16323\n9092\n17680\n\n1278\n3760\n4600\n5281\n3371\n4529\n2906\n5004\n4326\n4382\n3507\n1738\n3022\n1261\n2087\n\n2088\n5008\n6379\n4057\n3677\n5741\n1096\n3156\n4884\n5431\n3653\n6249\n1959\n4851\n\n3198\n1054\n5059\n1967\n5084\n4735\n1672\n1975\n3757\n5140\n4123\n1226\n5561\n3002\n1048\n\n4155\n6076\n4411\n4147\n1509\n1410\n1316\n2436\n5710\n3469\n5833\n3284\n2004\n5333\n2931\n\n3722\n6554\n4079\n3647\n6665\n2834\n6111\n1699\n2264\n3301\n4618\n6804\n\n18306\n2766\n15246\n16034\n\n10794\n8795\n6042\n14744\n8731\n\n9246\n15455\n7276\n1023\n\n4976\n5679\n3094\n6609\n3132\n6317\n7249\n3085\n2201\n4788\n3853\n7298\n\n6328\n8513\n10986\n8497\n3620\n\n8570\n6016\n3967\n7081\n2226\n3628\n1183\n7502\n2675\n\n3713\n4940\n3895\n5463\n1568\n1646\n1933\n4149\n4542\n5107\n2476\n6416\n5590\n4177\n\n1853\n3161\n5524\n4869\n4002\n4835\n5345\n3406\n3809\n6334\n3815\n4439\n4804\n4653\n\n2340\n1068\n6949\n4527\n2062\n1973\n7159\n6917\n7989\n5951\n3967\n\n7479\n1230\n6619\n5481\n4068\n6854\n1792\n6293\n2888\n7018\n4381\n\n43123\n\n12920\n10198\n13757\n10070\n3194\n10576\n\n26957\n29555\n\n5102\n11583\n4272\n\n5229\n1697\n7613\n1254\n3850\n3959\n3011\n8327\n1583\n5689\n\n3069\n5459\n1921\n4279\n2614\n3025\n1134\n2718\n3784\n3160\n2885\n5309\n3048\n3150\n\n15015\n5487\n11549\n16223\n\n1700\n1079\n5726\n2919\n4403\n4004\n4490\n4474\n5385\n4940\n2019\n2426\n1774\n5222\n4095\n\n2109\n1692\n3529\n4425\n5017\n1955\n2956\n5193\n1359\n3071\n5086\n3272\n1148\n1244\n5108\n\n3183\n5818\n5424\n3009\n9660\n10737\n7805\n4181\n\n4393\n2248\n6731\n1691\n1330\n2227\n3580\n\n3097\n6770\n4477\n2274\n10473\n6196\n6291\n10213\n\n4466\n1945\n4168\n3012\n5737\n2918\n1568\n6018\n3634\n2373\n2398\n1899\n5096\n6008\n2990\n\n6237\n4195\n4209\n6274\n5259\n6651\n6781\n4354\n7187\n2438\n1651\n1455\n\n5091\n5021\n1578\n1839\n2447\n1410\n1551\n1273\n2870\n2060\n6062\n4994\n4425\n1142\n2121\n\n25078\n34262\n\n3027\n1504\n2559\n3905\n4918\n1442\n5269\n1792\n1787\n7325\n2833\n6804\n\n10472\n3468\n6981\n4162\n5889\n10528\n3516\n4516\n\n5317\n1944\n2244\n1565\n2805\n2058\n3249\n5589\n5225\n4472\n4292\n4096\n1682\n3780\n4732\n\n2155\n1915\n1390\n6056\n4997\n5247\n3565\n5359\n4920\n3193\n6103\n5942\n\n5728\n1735\n2890\n2208\n4913\n3879\n6078\n3237\n2997\n3109\n1150\n4648\n\n4368\n6370\n5658\n2440\n3404\n1849\n5650\n3261\n4920\n4114\n3673\n6330\n4183\n5309\n\n3227\n2526\n7386\n6005\n5441\n8946\n2415\n8447\n9143\n\n2211\n5669\n1077\n3134\n1072\n3419\n5779\n3499\n5291\n2636\n5031\n4309\n4030\n6032\n3512\n\n40358\n\n31692\n14965\n\n12952\n19656\n13010\n15201\n\n3398\n5373\n2074\n4864\n2925\n3543\n" <> ...
day1_input
|> Day1.read_data()
|> Day1.puzzle1()
69626
day1_input
|> Day1.read_data()
|> Day1.puzzle2()
206780

Day2

defmodule Day2 do
  def decode(shape) do
    case shape do
      "A" -> :rock
      "B" -> :paper
      "C" -> :scissors
      "X" -> :rock
      "Y" -> :paper
      "Z" -> :scissors
    end
  end

  def decode_goal(goal) do
    case goal do
      "X" -> :loose
      "Y" -> :draw
      "Z" -> :win
      _ -> nil
    end
  end

  def decide_shape(elve, goal) do
    case {elve, goal} do
      {:rock, :win} -> :paper
      {:paper, :win} -> :scissors
      {:scissors, :win} -> :rock
      {:rock, :loose} -> :scissors
      {:paper, :loose} -> :rock
      {:scissors, :loose} -> :paper
      {_, :draw} -> elve
    end
  end

  def read_data(data) do
    data |> String.trim() |> String.split("\n")
  end

  def outcome(my_shape, other_shape) do
    case {my_shape, other_shape} do
      {:rock, :paper} -> :loose
      {:rock, :scissors} -> :win
      {:paper, :scissors} -> :loose
      {:paper, :rock} -> :win
      {:scissors, :rock} -> :loose
      {:scissors, :paper} -> :win
      _ -> :draw
    end
  end

  def score(shape, outcome) do
    shape_score =
      case shape do
        :rock -> 1
        :paper -> 2
        :scissors -> 3
      end

    outcome_score =
      case outcome do
        :win -> 6
        :loose -> 0
        :draw -> 3
      end

    shape_score + outcome_score
  end

  def puzzle1(data) do
    data
    |> Enum.map(fn match -> match |> String.split() |> Enum.map(&decode(&1)) end)
    |> Enum.map(fn match ->
      [elve, me] = match
      score(me, outcome(me, elve))
    end)
    |> Enum.sum()
  end

  def puzzle2(data) do
    data
    |> Enum.map(fn match ->
      [elve, goal] = String.split(match)
      elve = decode(elve)
      goal = decode_goal(goal)
      shape = decide_shape(elve, goal)
      score(shape, outcome(shape, elve))
    end)
    |> Enum.sum()
  end
end
{:module, Day2, <<70, 79, 82, 49, 0, 0, 18, ...>>, {:puzzle2, 1}}
defmodule Day2Test do
  use ExUnit.Case, async: false

  setup_all do
    {:ok,
     data: """
     A Y
     B X
     C Z
     """}
  end

  describe "Day2" do
    test "read_data", state do
      data =
        state[:data]
        |> Day2.read_data()

      [head | _] = data
      assert data |> length == 3
      assert head == "A Y"
    end

    test "score" do
      assert Day2.score(:rock, :win) == 7
      assert Day2.score(:scissors, :draw) == 6
    end

    test "decide shape" do
      assert Day2.decide_shape(:rock, :loose) == :scissors
    end

    test "total score part1", state do
      assert state[:data]
             |> Day2.read_data()
             |> Day2.puzzle1() == 15
    end

    test "total score part2", state do
      assert state[:data]
             |> Day2.read_data()
             |> Day2.puzzle2() == 12
    end
  end
end
{:module, Day2Test, <<70, 79, 82, 49, 0, 0, 23, ...>>, {:"test Day2 total score part2", 1}}
ExUnit.run()
.....
Finished in 0.00 seconds (0.00s async, 0.00s sync)
5 tests, 0 failures

Randomized with seed 627574
%{excluded: 0, failures: 0, skipped: 0, total: 5}
day2_input = File.read!("/Users/akode/dev/advent_of_code/aoc2022/day2.txt")
"A Z\nA Z\nC Y\nA X\nA X\nA Z\nC X\nA X\nC Y\nA Z\nB Y\nB Y\nC X\nC Y\nC X\nB Y\nA Y\nC Y\nB Y\nB Z\nB Y\nC X\nA Z\nC Y\nB Y\nB Y\nA Z\nB Y\nB Y\nB Y\nB Z\nB Y\nA Z\nB Y\nC Y\nB Y\nB Z\nC X\nB Z\nA X\nB Y\nB Z\nC Y\nA Z\nC Y\nA Z\nB Y\nC Y\nA Z\nA Z\nB Y\nC Y\nC X\nA Z\nB Z\nA Z\nB Y\nC X\nB Y\nB Y\nB Y\nA Y\nB Z\nC Y\nC X\nA Z\nB Y\nB Y\nB X\nA Z\nC X\nB Y\nB Y\nA Z\nA Z\nA X\nA X\nB Y\nC X\nA X\nA Z\nA Z\nB Y\nC Y\nB Z\nA X\nB Z\nA Z\nB Y\nA Z\nC Y\nA Z\nA X\nB Y\nC Y\nB Y\nA X\nB Z\nC Y\nB Y\nB Y\nA Z\nA X\nA X\nB Y\nC Y\nB X\nB Z\nC X\nB Y\nA Y\nB Y\nB Y\nB Y\nA X\nC Y\nA Z\nC Y\nC Y\nB Z\nB Y\nA Z\nA Z\nA Z\nB Y\nC Y\nB Z\nC X\nC Y\nB Z\nA X\nA Z\nC Y\nB Y\nC Y\nC Y\nC Y\nB Y\nB X\nB Y\nB Y\nC Y\nA X\nB Z\nB X\nC X\nB X\nC Y\nB Z\nB Y\nA X\nC Y\nC Y\nC X\nB Z\nB Y\nA Y\nB Z\nA Z\nB Y\nB Y\nB Z\nB Z\nC Y\nA Z\nA X\nA X\nC Y\nB Y\nA Z\nB Z\nA X\nA Z\nB Z\nC Y\nC Z\nA X\nA Y\nB Y\nC Y\nB Y\nC Y\nB Z\nB Y\nA Z\nC Y\nB Z\nB Y\nA Z\nA Y\nB Y\nB Y\nC Y\nA Z\nC Y\nB Y\nB Y\nA X\nA Z\nA Z\nB Y\nB Y\nB Z\nC Y\nC X\nB Z\nA Y\nB Z\nA X\nC X\nA Y\nB Z\nB Z\nA X\nC X\nC X\nA Z\nC Y\nA X\nA X\nC X\nA X\nB Z\nC Z\nB Z\nB Y\nB Y\nA Z\nA Z\nB Y\nA Z\nC Y\nC X\nB Y\nA X\nA X\nB Z\nC Y\nC Y\nA X\nB Z\nA X\nC X\nC X\nB Z\nC X\nB Z\nA X\nA Y\nA X\nA Z\nA X\nB Y\nC Y\nA X\nC Y\nA Z\nB Z\nA Z\nC Y\nA X\nA Z\nB Y\nA Z\nB Z\nB Z\nA Z\nB Z\nA X\nB Y\nB Z\nC X\nB Y\nB Y\nB Y\nB Y\nA X\nB Z\nB Z\nA Z\nA Z\nC Y\nB Y\nC X\nA X\nB Y\nB Y\nC X\nB Y\nA X\nC Y\nA Z\nB Y\nA Y\nB Z\nB Y\nA Z\nA X\nB Z\nC Y\nA Z\nC Y\nC X\nB Y\nB Z\nC X\nA Y\nB Z\nA Y\nB Z\nB Z\nB Y\nB Z\nC X\nB Y\nA X\nB Z\nA Z\nB Y\nA Z\nC Y\nC Y\nC X\nC X\nA X\nC X\nA X\nA X\nB Z\nB Y\nB Y\nB Y\nB Y\nC X\nC X\nA Z\nA Z\nC X\nC X\nC Y\nC Y\nC Y\nB Y\nA Z\nC Y\nB Z\nB Z\nB Y\nC X\nC X\nC Y\nC Y\nC X\nB Z\nB Z\nB Y\nC Y\nB Y\nA Z\nC Y\nA X\nB Y\nC Y\nC Y\nC Y\nB Y\nA Z\nB Y\nA X\nB Z\nC X\nA Z\nC X\nA Z\nB Z\nC Y\nC Y\nC Y\nC X\nB Z\nC X\nB Y\nB Z\nC X\nB X\nA Z\nB Z\nB Y\nC Y\nB Z\nC Y\nA X\nB Z\nC Y\nC Y\nB Z\nB Y\nC Y\nB Z\nC Y\nA Z\nC X\nC X\nC Y\nA Z\nC Z\nC Y\nB Y\nC Y\nB Y\nB Y\nB Z\nC X\nC X\nB Z\nB Z\nB Z\nA Z\nB Y\nB Y\nA X\nB Y\nC Y\nB Y\nC X\nC X\nB Y\nB Y\nA Y\nB Z\nB Y\nB Y\nC Y\nA Z\nC X\nA Y\nB Y\nB Z\nB Y\nA Y\nC Y\nA Y\nA Z\nB Y\nA Z\nC Y\nC Y\nB Y\nA Z\nB Y\nB Y\nA Z\nB Z\nB Y\nC X\nC Y\nB Z\nB Y\nB Y\nA Z\nC Z\nA Z\nA X\nC X\nB Z\nB Z\nC X\nC Y\nB Y\nB X\nA X\nC Y\nB Z\nB Y\nC X\nB Y\nA Z\nA Z\nA X\nC Y\nB Z\nB Y\nC X\nC X\nB Y\nA Z\nC Z\nB Y\nA Z\nC Y\nB Y\nC X\nA Z\nA Z\nA X\nC X\nA X\nC X\nC X\nA Z\nC X\nB Y\nA Z\nB Y\nB Y\nC Y\nC X\nA Z\nB Z\nB Y\nB Y\nA Y\nA Z\nB Y\nA Z\nB Z\nB Y\nC Y\nA Z\nB Y\nB Y\nB Y\nC Y\nC X\nA X\nA Z\nB Z\nB Y\nC Y\nB Z\nC X\nB Y\nC X\nA Z\nB Y\nB X\nB Y\nA Y\nA X\nA X\nC X\nC X\nB Y\nB X\nC Y\nA Z\nB Z\nC Y\nC Y\nB Y\nA Z\nC X\nA Z\nC Y\nB Z\nB X\nC X\nB X\nC X\nB Y\nC Y\nC Y\nB Z\nB Y\nB Z\nB Z\nA Z\nB Y\nA Y\nB Z\nC X\nC Y\nC X\nA Z\nB Z\nC Y\nB Y\nB Z\nC X\nB Y\nA Y\nA X\nA X\nC Y\nB X\nC X\nB Z\nA Z\nA Y\nB Z\nC X\nC X\nB Y\nA X\nB Z\nC Y\nB X\nB Z\nC Y\nB Y\nC Y\nB Z\nB Y\nB Z\nB Y\nC X\nB Y\nC X\nB Z\nB Z\nC X\nB Z\nA X\nB X\nB Y\nA X\nB Z\nC X\nB Z\nB Y\nB Y\nC X\nA Y\nB Z\nB Z\nB Y\nB Y\nB Z\nC Y\nB Z\nC Y\nC X\nA Z\nC X\nA X\nC Y\nB Y\nC X\nA Z\nB Y\nA Z\nA Z\nB X\nC Y\nB Z\nC Y\nB Y\nB Z\nA X\nB Z\nA X\nC X\nB Z\nB Y\nC X\nC Y\nC Y\nB X\nC X\nC X\nB Z\nC Y\nB Z\nB Y\nB Z\nC Y\nB Y\nC Y\nC X\nB Y\nB Y\nB Z\nA Z\nC X\nA Z\nB Y\nB Z\nA Z\nC Y\nA Z\nB Y\nA Z\nA Z\nC Y\nA Y\nB Y\nA Y\nC X\nB Y\nC X\nB Z\nC Y\nA Z\nC X\nC X\nB Z\nC Z\nC Z\nB Y\nB Y\nC Y\nC Y\nA Z\nC Y\nC Y\nC Y\nA Z\nB Z\nC Y\nB Y\nC Y\nC X\nC X\nB X\nB Y\nC Y\nA Y\nB Y\nB Z\nB Y\nA Y\nB Y\nB X\nC X\nC Z\nC Y\nC Y\nC Y\nB Z\nB X\nC Y\nB Z\nC X\nC Y\nA Z\nA Y\nB Y\nC X\nA Z\nB Y\nC Y\nB Z\nA Z\nA Z\nB Y\nA Z\nC Y\nA X\nC Y\nB Z\nB Z\nB Z\nB Y\nB Y\nA Z\nA Z\nB Y\nC X\nA Z\nC Y\nB Y\nA Z\nC Y\nA Z\nB Z\nB Z\nA Y\nB Y\nB Y\nB Z\nC Z\nB Y\nB X\nB Y\nC X\nB Z\nC Y\nB Z\nA Y\nB Z\nA Z\nA X\nA Z\nC X\nC X\nB Y\nC X\nC Y\nA Z\nB Z\nB Y\nA Z\nB Z\nB Z\nB Z\nC Y\nB Y\nA X\nC Y\nC Y\nC X\nA X\nC Y\nB Y\nC X\nB Z\nA Y\nB X\nB Y\nA Z\nB Y\nB Y\nB Y\nB Z\nC X\nB Z\nB Z\nC X\nB Y\nA Y\nB Y\nC Y\nA Z\nC Z\nB Y\nB Z\nB Z\nC Y\nA Z\nC Y\nC X\nC Y\nB Y\nA X\nA X\nB Z\nC Y\nB Z\nB Y\nA Y\nC X\nA Z\nB Z\nC Y\nC Z\nC X\nB Y\nC X\nA Y\nA Y\nB Z\nC X\nB X\nC X\nB Y\nB Z\nB Z\nB Y\nC Y\nB Y\nB Y\nA Z\nB Z\nB Y\nC X\nB Z\nB Y\nB Y\nC Y\nC Z\nC X\nB Y\nA X\nC Y\nC X\nB Z\nC Y\nA X\nB Y\nA Y\nB Y\nC X\nC Y\nC X\nA X\nB Z\nC X\nB Y\nA Z\nC X\nB Y\nA Z\nB Y\nB Y\nB Y\nA Z\nA X\nC X\nC Y\nC Y\nB Y\nB Y\nB Z\nA Y\nC X\nC X\nB Y\nB Y\nB Z\nA X\nC X\nC X\nB X\nA X\nB Z\nB Y\nC X\nA X\nB Y\nC Y\nA X\nB Y\nC X\nB Z\nC Z\nB X\nC Y\nB Y\nC Y\nA Z\nC Y\nB Z\nC X\nB Z\nC X\nC Y\nC X\nC Y\nC Z\nC X\nC X\nB Y\nC Y\nC X\nC X\nB Z\nB Z\nA X\nC Y\nC Z\nB Y\nC Z\nC Y\nC X\nC X\nB Y\nC Y\nA Y\nB Y\nA Y\nB Y\nB Y\nB Y\nC Y\nC Z\nB Y\nC X\nC X\nB Z\nB Y\nB Z\nC Y\nB Z\nC X\nB Z\nB Y\nB Y\nA Z\nA X\nB X\nA X\nC X\nC Y\nB Y\nA X\nB Z\nB Y\nB Y\nA X\nC X\nC X\nB Y\nB Y\nC Y\nC Y\nB Z\nB Y\nB Y\nB Y\nC Y\nA X\nB Y\nC Y\nB Z\nB Y\nB Y\nB Z\nB Y\nB Y\nB Z\nB Y\nB Y\nC Y\nA Z\nB Z\nA Y\nB Y\nC Y\nB Z\nB Y\nB Y\nC X\nA X\nC Z\n" <> ...
day2_input
|> Day2.read_data()
|> Day2.puzzle1()
12855
day2_input
|> Day2.read_data()
|> Day2.puzzle2()
13726

Day3

defmodule Day3 do
  def read_data(data) do
    data
    |> String.trim()
    |> String.split("\n")
    |> Enum.map(&to_charlist(&1))
  end

  def get_duplicate(backpack) do
    [comp1, comp2 | _] = Enum.map(backpack, &MapSet.new(&1))
    MapSet.intersection(comp1, comp2) |> MapSet.to_list() |> List.first()
  end

  def get_priority(char) do
    cond do
      char >= 97 -> char - 96
      true -> char - 38
    end
  end

  def puzzle1(data) do
    data
    |> Enum.map(&Enum.chunk_every(&1, div(length(&1), 2)))
    |> Enum.map(fn backpack ->
      backpack
      |> get_duplicate
      |> get_priority
    end)
    |> Enum.sum()
  end

  def puzzle2(data) do
    data
    |> Enum.chunk_every(3)
    |> Enum.map(fn group ->
      [elve1, elve2, elve3 | _] = Enum.map(group, &MapSet.new(&1))

      elve1
      |> MapSet.intersection(elve2)
      |> MapSet.intersection(elve3)
      |> MapSet.to_list()
      |> List.first()
      |> get_priority
    end)
    |> Enum.sum()
  end
end
{:module, Day3, <<70, 79, 82, 49, 0, 0, 14, ...>>, {:puzzle2, 1}}
defmodule Day3Test do
  use ExUnit.Case, async: false

  setup_all do
    {:ok,
     data: """
     vJrwpWtwJgWrhcsFMMfFFhFp
     jqHRNqRjqzjGDLGLrsFMfFZSrLrFZsSL
     PmmdzqPrVvPwwTWBwg
     wMqvLMZHhHMvwLHjbvcjnnSBnvTQFn
     ttgJtRGJQctTZtZT
     CrZsJsPPZsGzwwsLwLmpwMDw
     """}
  end

  describe "Day3" do
    test "read data", state do
      data = Day3.read_data(state[:data])
      assert length(data) == 6
    end

    test "get priority" do
      assert Day3.get_priority(?a) == 1
      assert Day3.get_priority(?A) == 27
      assert Day3.get_priority(?z) == 26
      assert Day3.get_priority(?Z) == 52
    end

    test "puzzle1", state do
      assert state[:data]
             |> Day3.read_data()
             |> Day3.puzzle1() == 157
    end

    test "puzzle2", state do
      assert state[:data]
             |> Day3.read_data()
             |> Day3.puzzle2() == 70
    end
  end
end
{:module, Day3Test, <<70, 79, 82, 49, 0, 0, 22, ...>>, {:"test Day3 puzzle2", 1}}
ExUnit.run()
....
Finished in 0.00 seconds (0.00s async, 0.00s sync)
4 tests, 0 failures

Randomized with seed 627574
%{excluded: 0, failures: 0, skipped: 0, total: 4}
input_day3 = File.read!("/Users/akode/dev/advent_of_code/aoc2022/day3.txt")
"LLBPGtltrGPBMMsLcLMMVMpVRhhfCDTwRwRdTfwDllRRRDhC\ngNFJHJFgtZFJjZJHNNFWZWZwwDjCwSDhfCDbdwjfwDTTDT\ngmQNZnZNHWnqmQpLtVLMBsPpBqrL\nHlHldQtHlctzppdQtjdczHhJRnnhGNVmVRJmVjCVFCNh\nLgWNgggZJZGFhCZr\nDbqPswwMvDPqzlBNHtzfHdwd\ntJgtJwwCtNvPHHPtHzDsdRTsBRDDWgWTgT\nQhLQjLGjZQFlFZmnmGLDrzWfRldrTrzTBRWTzs\nbFFmFZjhSFHvBCvCvJpb\nMSGcvnvMGMJgWJDpdndZwBnppfCp\nVPVfQQVbshZNZwdNDwNs\nLtLbjmQRLmVhQtTbfgWjJgFFcrqqrGSqWg\nfHfCNCwwHfGhcntntrrgHrQnrn\nFVqpSpbPpjSVMjqvVmVvMzlzwJnbtnnlzQQlrWzJgt\nPTqqRRPSRSmqSpPpSpRZwGCLGscCNLZZZTNdNZ\npQQQslVSVzzCQnZSlplzbLcHZHcrrrbZqFbZjbFm\ngWtvPgdMDDtFDHHjJJbbccbrLW\nMhNvwwDfDfdtvRQnpFNNTlSRSn\nZTnSnTTzqvFmVzvWWm\nClpCgltHNrtgsHdpLCHtDCNLVvQvVwVmwcsWQGMMQvcGcFcv\nJmrgCHCNJtlmHmNhnJjnnnjJhPfhSJ\nBgRRZTgHHvRTRmRNLNNhQWlmGFfJlWlhsQshpF\nqPqSSttwnnzqqqwtVrPwMthFsJllJJlGhpJhWJQlhVQd\nMjMwScnDPzcwjtqDtztnctrvgNZTTvCvLgvQbLbvjTBvBg\nSWQSbbqTTbPcfMZSwZZwwn\ndghjghmNDmGsGgdnfmtMRCLCCRncfc\npJDJNdsNMMhpssgdprBTBzWlpBWlllWb\nTwNLNZTwWCWLwWCSTZSLzWHGrDHHPmGdDHvndGdNfvMm\nBgpjtpgjBjVbRjQRhVsDnvgGgPnGdrmvnMDfrf\nrhRjRssQJplRtVbpthblbbLSLzFCJZFqLLFWCzqcqzLL\nPBrdPMtBPvCQBVBjCfWPqSHbszhGGnsfSG\nJpmDwJgWJgNzmShhmfSGzh\npRwNcNpFZNZRWgcNplpjVCMVjdvdMQtCMLZjMZ\nlDrcnnlLqLRcDDZRLjFVTHzGCLGVPzGPVWGB\npNwHpdmsNJsbpwsbzJTCPWTVFzzQTWCQ\nvbhswdtdwfdsmtNSssHwvllvMcZjnjcnZqlgMDZglM\nGVVtJGtzVFsVsDTH\nmQRgcBRmRLnBjrtFjCCrHmFF\ngqpBnlRpgZcvdSdlMdSvMt\ntMSCNGSflffNhnnGqlPPsrzWPrTrVpWr\nbZHbmDBQmbDZQdbDcRFZZBTTWWWwqVzszWjrFPVwrzqq\nHQBLHmQVQLDdCggMfgMNLvNG\nHHNDzNJPJPmdPcNGGGhnhwnVhCQBwBjQ\nbsSbLfrLtRSLRSRRRsBwhCpfpCzlwCBVjlCV\nzvvsvqLtZqLtzRsqTrggRMHJNWJgHHHNJcgWNPdHcH\nqgbNvqbgmmZgZLvZqgnZzlpzpzHtVPzttGPrrnnl\njwswGjQDMsQMjdBwdcjCHVtcPVpCVCrPlVSrpc\nGsFWBfhGBfDFDFWqNbLNqbgvqbbvfN\nHgwWqtcqHNWgnHcNNCfvJCCJJfJGvnPfrR\nsbDhZSmdBbsSdmSDdrjjffRvdjPrprCd\nvvZbSFFlFHtqFqqWNc\nZRjnbRsHlncZGjTRTfFVSQBQppQvvFBHpF\nzrLwMdhDhqJJttDQSldQVPQSlSfPlV\nhCWWCzqWnmcZlRRW\nHfgfQflHjWgRQRdRBWVsnbvvscbbbwvmbHncSc\ntJGLtPPGZPwVvSSPhw\nCLGTLZqJtMGqLDFFDZZJFZJpWjRpVNRWpllDpjlBfgVjlp\nrhhGZZhLNhPmfJqvfLlq\ndHRTHRHQQWcTCRTHmmjJgfqqlGmgWgql\nCCwRzTRRdCCRSQwzRcppprZtrMhGBMZMnDSt\nWfffvnSnfSBshwsjhlvGlh\nZHpFNTmppVmNzVVmmFMZzbwwjHGrGlPhCGrljbgHsg\npLZMmqVsZVMMVVscDfdtSSStqcRRdn\nRhRbLzRLHLCPmzznHLbzCRTJhdTVSJJVSjdFFNFFNTJv\nMGgMfpMsBgpnMtGfnfwBtDBjFVdNSSSFdvJSQSpTJdJjNv\nlMsBgDMsblmRblnz\nClNcJZttLfLvvRQzQWwRQN\nhrpMdqMspsrGDdMphhdMMMMHBmRWmSVrRVzVTzQBQvSmzVWV\nppHDMGhMMDbGMdDMGbgFbgbMlJJnjjZtZfLPcfcngZfPPfCR\nZRslLRgCclZLZzQghQhfrbfGbJ\npVSHpBBBBDVDqDBldVzfrMzQbfSTSJrzzJrJ\nDqqHnBDlpNDVVnpnjtDtNjCvFLcsFFPZRcPsNNmPcFcP\nLmLWSmSRNdcpcRHFHrWzWHbMbwZlZlPSbTjlwPbTPJTf\nDttBsvhnhqvGGBhGtBVNBVqJlPwslMMPJwTjZbbZPTfbPs\nCDthQvVNVFCHHWCFdr\nRRtCWSzQZdRMrtRWrSztMggcGDfQTcfFTGqTLgGDLc\nbnVhnvPHhhdJJBTLDGcDTcBvvD\npmbnhmPPmHwdCjmdrRtCdj\nlTPzwhzmHpTvrDCDHJnsNN\ntdgtbMMBbWdFbtqJCnsrqnMMDsrq\nFjWdtgLSWttWtLSWtDWBjGGmwGlzTRwPTQGhlQQm\nwcbnTtTppNLrntznTBBccCGrVldRrZqdqRCZdFZCVZ\nJfHDgjgPPfRRgRlLRddR\njhDhhLMfmJjMjDbNSTzbbbtmttmN\nCfGlvzpvpTjzzCWjvDlfvbbJbCRSdSRhsSQCMhdbhR\nwqrSmrLHHNcLqrrLBNsndssnnhPshnsQwbnJ\nNtcmBLcNVDWzjSvWtv\nvZPCSCvCJffvVvmCmPqCSlDSscczHDRcwcHzRlRHHs\nLFGFNnGrdQttNMFpzpMRRDslsJwsJH\ngjtLnFBJrLvhZvCbZhqB\nDBcjVFjDhQMSJVZbHZbl\nnfmsqppnLfTnfmMmzppwgllSrbSHHtllqbtSwZ\nTRzTnfRWnfdzWssfnRfRpncQPBhdDjjDCPcMQcCBGPPj\nNSjWCHjNHjpPWPpSFWdtqBMBBFVBvqvJGJwqBt\ngQllgDrnhQQDGRshRsZfVtVMRqwMtccVJcBtvRqw\nDQrzrDzhQgrsZLrZjWSSHNTWCjjNGTLH\nCgdcCFcbTbBzPgmNRmpptP\nrsZtsvVvHZZzPmqVNPzNmV\nHZjrwrjnjtHSHwDGdFhCdhWWJnWchCFJ\nRMTqQMRJqPtBtGBPtWjN\nssHfSfShCwwbhsbHhhsmSfhSGNpCpNCjBBBLptcGtpzBBBWW\nHnwrSFwffHsFwrSSjfHglJJlTgZdFdgZRZTDDM\npDLDWlDSlJDmzSJnDScRPLGGvqFqLPccGLgv\nCZHfwNMVNjsHNNqPgcbcBbRQGQ\ndCffZCjVCdCHHTmnlSgTlTSrlStp\nbFtlLCvLlVjpCGPJndrrMMCDDCnrMg\nhRsTwcZcBjZRJrfMDnsHrJnH\nmNZqcTSSBTScNzVQFtGtjpFtjmGG\nbjHdLrHjRWpDCtLzhzps\nlZcGfTvQcQfvlqqcNCcBvVwtGzmzthmwmpthMDmswgMt\nNcqflNQTBTTvvQSvqSVvQJbHPHbHCRJdndJPSHjWHb\nCVmRncrRVrhcmsBgfmtfdJsJmt\nbZHvZZDJwpWtdZgtGNGd\nvSbwHDMFMJqPQqQvvSPQqpSwjRcTVTLjLRhVCLFLjLFnFzCC\nmtffsmBwfwBDBmmsLsHqtpftGrMVMPSMPsVvhNvFrGPMvjNV\nTQTQCRWjJcdcQQSPrhhPSvVGPF\ncTRJCnldWJZlTgbWgbdbpqfqmppjmtljpqzmjpLw\nNNPmrmPWmrSSNNPmnglghmCvLCCflh\nLFbsDQMQFtQFHbQHqhvnngCftpcllptJgJ\nbDjsGqLLdRVjPZPP\ntgrbBQlbtRblwtRGrbCNswDDCsvFszpssCss\nSJVMhSZfHvpdhphN\nSMLpWZSSZMjfgGBgRtbQgl" <> ...
input_day3
|> Day3.read_data()
|> Day3.puzzle1()
7793
input_day3
|> Day3.read_data()
|> Day3.puzzle2()
2499

Day4

defmodule Day4 do
  @pattern ~r/(?<elve1_l>\d+)-(?<elve1_h>\d+),(?<elve2_l>\d+)-(?<elve2_h>\d+)/

  def read_data(data) do
    data
    |> String.trim()
    |> String.split("\n")
    |> Enum.map(fn pair ->
      m = Regex.named_captures(@pattern, pair)
      for {key, val} <- m, into: %{}, do: {key, String.to_integer(val)}
    end)
  end

  def puzzle1(data) do
    data
    |> Enum.map(fn m ->
      cond do
        m["elve1_l"] >= m["elve2_l"] and m["elve1_h"] <= m["elve2_h"] -> 1
        m["elve1_l"] <= m["elve2_l"] and m["elve1_h"] >= m["elve2_h"] -> 1
        true -> 0
      end
    end)
    |> Enum.sum()
  end

  def puzzle2(data) do
    data
    |> Enum.map(fn m ->
      cond do
        m["elve1_l"] > m["elve2_h"] -> 0
        m["elve1_h"] < m["elve2_l"] -> 0
        true -> 1
      end
    end)
    |> Enum.sum()
  end
end
{:module, Day4, <<70, 79, 82, 49, 0, 0, 15, ...>>, {:puzzle2, 1}}
defmodule Day4Test do
  use ExUnit.Case, async: false

  setup_all do
    {:ok,
     data: """
     2-4,6-8
     2-3,4-5
     5-7,7-9
     2-8,3-7
     6-6,4-6
     2-6,4-8
     """}
  end

  describe "Day3" do
    test "read data", state do
      data = Day4.read_data(state[:data])
      assert length(data) == 6
    end

    test "puzzle 1", state do
      assert state[:data]
             |> Day4.read_data()
             |> Day4.puzzle1() == 2
    end

    test "puzzle 2", state do
      assert state[:data]
             |> Day4.read_data()
             |> Day4.puzzle2() == 4
    end
  end
end
{:module, Day4Test, <<70, 79, 82, 49, 0, 0, 18, ...>>, {:"test Day3 puzzle 2", 1}}
ExUnit.run()
...
Finished in 0.00 seconds (0.00s async, 0.00s sync)
3 tests, 0 failures

Randomized with seed 627574
%{excluded: 0, failures: 0, skipped: 0, total: 3}
input_day4 = File.read!("/Users/akode/dev/advent_of_code/aoc2022/day4.txt")
"8-18,10-19\n12-69,8-15\n62-77,36-50\n26-27,26-91\n16-23,24-63\n17-43,18-44\n29-68,29-70\n15-90,28-91\n8-39,10-40\n47-64,27-63\n8-77,78-95\n3-65,66-71\n20-22,21-98\n52-53,53-98\n29-30,29-44\n86-90,38-87\n33-99,31-31\n62-80,82-90\n45-55,33-54\n57-62,58-63\n8-59,8-98\n7-23,1-22\n12-36,22-37\n1-31,32-80\n94-96,46-95\n5-90,4-40\n5-5,6-52\n74-86,7-87\n1-4,6-38\n49-65,49-64\n21-21,22-99\n48-61,11-88\n46-51,46-50\n13-87,88-88\n5-6,6-99\n9-40,52-96\n4-93,5-92\n78-88,77-86\n39-72,71-73\n31-90,19-91\n52-53,53-94\n2-4,3-62\n92-95,46-91\n41-42,41-94\n96-98,8-97\n9-75,9-74\n75-85,67-76\n27-32,29-32\n69-93,70-94\n17-80,18-80\n68-68,12-69\n36-80,35-60\n41-86,41-42\n18-82,83-83\n48-97,90-92\n1-57,16-58\n39-89,39-88\n17-17,16-53\n98-99,8-97\n24-71,9-48\n37-38,37-52\n9-80,10-80\n1-18,19-57\n55-67,58-73\n82-84,85-85\n23-92,22-87\n9-97,92-96\n11-93,94-98\n16-93,17-17\n81-97,63-80\n67-92,67-92\n63-67,62-64\n15-66,67-81\n13-20,13-13\n83-83,4-82\n10-54,6-6\n13-69,8-11\n18-19,18-94\n9-46,8-19\n31-97,62-96\n35-94,95-95\n21-56,57-57\n3-44,3-39\n24-95,79-89\n33-59,34-34\n23-25,21-26\n71-97,38-98\n37-76,38-77\n77-86,64-87\n2-12,1-70\n34-96,15-97\n16-75,74-76\n4-99,4-99\n12-89,11-12\n6-24,5-7\n10-43,11-88\n11-44,45-83\n24-95,2-96\n10-73,2-11\n3-82,16-31\n20-21,20-30\n22-87,86-89\n44-44,43-47\n56-84,56-57\n8-80,9-86\n1-50,5-51\n9-30,8-9\n50-87,27-70\n37-96,96-96\n9-79,46-81\n3-98,3-97\n65-83,27-38\n51-56,1-56\n7-97,8-97\n33-91,32-90\n38-86,87-87\n8-91,4-92\n8-89,25-88\n88-99,48-98\n70-80,24-69\n28-55,43-50\n46-70,7-47\n66-94,67-93\n18-43,93-99\n29-61,29-49\n19-71,18-71\n21-36,21-36\n61-63,62-81\n4-5,5-95\n90-93,63-89\n1-23,4-22\n66-83,50-82\n63-92,81-98\n29-99,29-99\n4-8,8-99\n30-47,31-36\n3-94,93-99\n52-52,51-87\n76-76,77-80\n2-95,6-96\n8-97,9-48\n12-79,11-78\n25-95,14-94\n76-96,3-33\n1-96,76-99\n3-3,2-90\n76-91,75-76\n12-83,11-11\n3-33,19-48\n12-98,12-13\n15-94,16-98\n1-2,4-90\n25-59,26-50\n27-85,84-85\n22-75,22-22\n30-39,30-38\n4-95,4-95\n24-49,10-48\n33-34,34-79\n3-62,33-61\n4-17,3-5\n27-58,59-59\n72-98,73-98\n28-86,87-95\n27-57,28-56\n49-98,40-92\n30-85,84-92\n76-78,75-75\n33-84,83-83\n56-64,42-63\n69-90,27-90\n67-70,66-67\n52-66,56-79\n3-81,2-82\n9-92,93-96\n42-93,94-94\n20-32,33-96\n41-42,42-94\n7-37,6-17\n17-44,18-28\n79-83,66-78\n2-29,1-86\n25-29,20-29\n38-77,38-38\n59-59,59-99\n71-96,11-96\n48-96,17-85\n71-75,67-75\n75-82,76-81\n8-58,8-58\n45-91,35-46\n10-14,15-80\n87-88,3-99\n1-3,7-57\n24-37,24-38\n10-74,75-81\n5-92,5-5\n73-96,96-97\n22-84,84-85\n91-91,3-90\n18-20,19-20\n4-4,3-91\n29-30,30-65\n57-64,22-50\n25-88,24-68\n30-94,94-96\n15-42,16-90\n17-96,71-87\n36-89,35-37\n18-71,70-70\n13-36,12-94\n47-96,46-48\n2-94,55-95\n82-82,3-82\n3-84,1-48\n34-85,34-85\n9-95,8-95\n1-28,1-29\n98-98,52-85\n55-56,30-55\n20-59,19-89\n55-56,50-57\n96-96,20-95\n44-50,15-67\n73-74,56-75\n54-98,38-55\n54-93,54-86\n6-94,7-95\n23-24,23-34\n52-83,9-80\n2-95,1-13\n52-90,29-91\n66-89,66-66\n10-10,11-94\n65-73,64-97\n8-93,62-92\n71-72,72-85\n2-58,59-59\n46-46,47-61\n8-8,8-84\n6-75,76-76\n47-97,24-48\n19-19,20-71\n13-94,4-87\n47-78,48-78\n20-74,21-35\n11-46,11-46\n11-78,77-79\n13-74,14-73\n2-98,1-97\n30-30,31-35\n1-14,2-99\n11-93,10-11\n3-77,7-78\n41-56,40-55\n26-92,97-97\n96-98,17-83\n95-99,8-94\n62-92,47-61\n4-93,3-61\n3-86,2-16\n80-99,21-96\n6-90,47-91\n6-6,7-91\n13-91,13-13\n53-91,52-94\n1-86,4-86\n53-90,54-90\n7-62,7-62\n11-89,11-90\n17-18,18-92\n14-35,11-34\n6-99,19-98\n35-59,34-59\n65-82,68-83\n2-95,3-38\n2-92,3-92\n51-52,43-52\n9-41,9-49\n8-97,8-31\n20-67,66-97\n4-87,37-86\n20-21,20-89\n16-87,15-88\n59-68,60-68\n46-83,86-90\n15-55,9-16\n3-8,7-79\n96-98,41-92\n16-75,62-82\n79-99,62-78\n1-96,97-97\n46-60,45-45\n68-68,41-67\n22-87,21-86\n80-81,80-84\n1-30,31-50\n49-91,49-90\n8-74,73-78\n32-32,31-40\n3-89,4-89\n50-61,51-61\n36-81,35-37\n4-97,4-98\n39-87,38-87\n8-98,98-99\n4-96,95-97\n1-53,3-87\n19-20,19-90\n13-78,12-79\n1-2,2-75\n2-42,2-90\n3-16,3-23\n32-72,87-98\n57-88,60-88\n15-28,29-29\n3-4,4-99\n48-48,46-50\n91-94,87-95\n16-97,98-99\n38-38,48-94\n30-63,7-62\n7-98,8-8\n4-50,49-50\n17-49,18-18\n7-75,6-6\n70-88,73-87\n3-45,3-44\n87-94,36-48\n66-73,13-65\n34-75,8-73\n2-53,2-82\n1-85,71-86\n2-7,6-88\n2-4,4-93\n20-20,13-19\n38-71,26-71\n14-88,20-88\n57-81,56-82\n13-85,6-56\n34-74,34-34\n64-64,25-63\n34-35,34-35\n18-29,13-29\n39-40,15-41\n44-71,43-70\n39-75,37-37\n18-78,18-90\n49-50,49-94\n17-96,1-16\n45-56,48-55\n48-79,48-80\n6-93,5-93\n12-34,11-99\n19-22,18-19\n3-76,2-65\n8-99,94-97\n37-42,37-42\n20-88,17-92\n15-49,15-" <> ...
input_day4
|> Day4.read_data()
|> Day4.puzzle1()
448
input_day4
|> Day4.read_data()
|> Day4.puzzle2()
794

Day5

defmodule Day5 do
  @move_pattern ~r/move (?<quantity>\d+) from (?<from>\d+) to (?<to>\d+)/

  defmodule Move do
    defstruct [:quantity, :from, :to]
  end

  def read_data(data) do
    [initial_state, moves] = String.split(data, "\n\n")
    [_ | stacks] = initial_state |> String.split("\n", trim: true) |> Enum.reverse()
    # stack_labels = parse_stack_labels(stack_labels)
    {_, stacks} = Enum.map_reduce(stacks, %{}, fn item, acc -> {:ok, add_to_stack(item, acc)} end)

    moves =
      moves
      |> String.split("\n", trim: true)
      |> Enum.map(&parse_move(&1))

    {stacks, moves}
  end

  def add_to_stack(line, acc \\ %{}) do
    line = line |> parse_stack_line

    Map.merge(line, acc, fn _k, v1, v2 ->
      v1 ++ v2
    end)
  end

  def parse_stack_line(stack_line) do
    stack_line
    |> String.to_charlist()
    |> Enum.chunk_every(4)
    |> Enum.with_index(1)
    |> Enum.map(fn {stack, i} ->
      {item, _} = List.pop_at(stack, 1)

      if item != 32 do
        {i, [to_string([item])]}
      end
    end)
    |> Enum.filter(&(!is_nil(&1)))
    |> Map.new()
  end

  def parse_stack_labels(label_line) do
    label_line
    |> String.split()
    |> Enum.map(fn label ->
      label |> String.trim() |> String.to_integer()
    end)
  end

  def parse_move(move_string) do
    m = Regex.named_captures(@move_pattern, move_string)
    m = for {key, val} <- m, into: %{}, do: {String.to_existing_atom(key), String.to_integer(val)}
    struct(Move, m)
  end

  def make_move(state, move) do
    {item, state} =
      Map.get_and_update(state, move.from, fn current ->
        [head | tail] = current
        {head, tail}
      end)

    state = Map.update!(state, move.to, fn current -> [item | current] end)

    if move.quantity > 1 do
      move = %{move | quantity: move.quantity - 1}
      make_move(state, move)
    else
      state
    end
  end

  def make_move2(state, move) do
    {item, state} =
      Map.get_and_update(state, move.from, fn current ->
        Enum.split(current, move.quantity)
      end)

    Map.update!(state, move.to, fn current -> item ++ current end)
  end

  def to_answer(state) do
    state
    |> Enum.map(fn {_key, val} ->
      [head | _] = val
      head
    end)
    |> List.to_string()
  end

  def puzzle1(data) do
    {initial_state, moves} = read_data(data)

    {_, end_state} =
      Enum.map_reduce(moves, initial_state, fn m, acc ->
        {:ok, make_move(acc, m)}
      end)

    end_state |> to_answer
  end

  def puzzle2(data) do
    {initial_state, moves} = read_data(data)

    {_, end_state} =
      Enum.map_reduce(moves, initial_state, fn m, acc ->
        {:ok, make_move2(acc, m)}
      end)

    end_state |> to_answer
  end
end
{:module, Day5, <<70, 79, 82, 49, 0, 0, 35, ...>>, {:puzzle2, 1}}
defmodule Day5Test do
  use ExUnit.Case, async: false

  setup_all do
    {:ok,
     data: """
         [D]    
     [N] [C]    
     [Z] [M] [P]
      1   2   3 

     move 1 from 2 to 1
     move 3 from 1 to 3
     move 2 from 2 to 1
     move 1 from 1 to 2 
     """}
  end

  describe "Day5" do
    test "parse stack labels" do
      stack_labels = " 1   2   3 "
      assert stack_labels |> Day5.parse_stack_labels() |> length == 3
      assert Day5.parse_stack_labels(stack_labels) == [1, 2, 3]
    end

    test "parse stack line" do
      assert Day5.parse_stack_line("[Z] [M] [P]") == %{1 => ["Z"], 2 => ["M"], 3 => ["P"]}
      assert Day5.parse_stack_line("[Z]     [P]") == %{1 => ["Z"], 3 => ["P"]}
    end

    test "add to stack" do
      assert "[Z] [M] [P]"
             |> Day5.add_to_stack() == %{1 => ["Z"], 2 => ["M"], 3 => ["P"]}

      assert "[A]     [B]"
             |> Day5.add_to_stack(%{1 => ["Z"], 2 => ["M"], 3 => ["P"]}) == %{
               1 => ["A", "Z"],
               2 => ["M"],
               3 => ["B", "P"]
             }
    end

    test "read initial configuration", state do
      {initial_state, _} = Day5.read_data(state[:data])
      assert initial_state == %{1 => ["N", "Z"], 2 => ["D", "C", "M"], 3 => ["P"]}
    end

    test "parse move" do
      assert "move 1 from 2 to 1"
             |> Day5.parse_move() == %Day5.Move{quantity: 1, from: 2, to: 1}
    end

    test "read moves", state do
      {_, moves} = Day5.read_data(state[:data])
      assert length(moves) == 4
    end

    test "move", state do
      {initial_state, [move | _]} = Day5.read_data(state[:data])

      assert Day5.make_move(initial_state, move) == %{
               1 => ["D", "N", "Z"],
               2 => ["C", "M"],
               3 => ["P"]
             }
    end

    test "puzzle 1", state do
      assert Day5.puzzle1(state[:data]) == "CMZ"
    end

    test "puzzle 2", state do
      assert Day5.puzzle2(state[:data]) == "MCD"
    end
  end
end
{:module, Day5Test, <<70, 79, 82, 49, 0, 0, 33, ...>>, {:"test Day5 puzzle 2", 1}}
ExUnit.run()
.........
Finished in 0.00 seconds (0.00s async, 0.00s sync)
9 tests, 0 failures

Randomized with seed 627574
%{excluded: 0, failures: 0, skipped: 0, total: 9}
input_day5 = File.read!("/Users/akode/dev/advent_of_code/aoc2022/day5.txt")
"[D]                     [N] [F]    \n[H] [F]             [L] [J] [H]    \n[R] [H]             [F] [V] [G] [H]\n[Z] [Q]         [Z] [W] [L] [J] [B]\n[S] [W] [H]     [B] [H] [D] [C] [M]\n[P] [R] [S] [G] [J] [J] [W] [Z] [V]\n[W] [B] [V] [F] [G] [T] [T] [T] [P]\n[Q] [V] [C] [H] [P] [Q] [Z] [D] [W]\n 1   2   3   4   5   6   7   8   9  \n\nmove 1 from 3 to 9\nmove 2 from 2 to 1\nmove 3 from 5 to 4\nmove 1 from 1 to 8\nmove 1 from 3 to 9\nmove 1 from 5 to 7\nmove 1 from 5 to 3\nmove 4 from 4 to 2\nmove 2 from 3 to 4\nmove 1 from 3 to 2\nmove 6 from 1 to 5\nmove 1 from 4 to 3\nmove 1 from 3 to 9\nmove 4 from 2 to 4\nmove 4 from 8 to 7\nmove 3 from 2 to 6\nmove 1 from 2 to 7\nmove 5 from 5 to 6\nmove 1 from 5 to 8\nmove 5 from 8 to 7\nmove 7 from 4 to 6\nmove 15 from 6 to 4\nmove 1 from 8 to 7\nmove 1 from 1 to 5\nmove 1 from 2 to 4\nmove 2 from 4 to 8\nmove 1 from 5 to 2\nmove 5 from 6 to 4\nmove 2 from 2 to 1\nmove 1 from 9 to 4\nmove 1 from 6 to 9\nmove 3 from 9 to 3\nmove 3 from 4 to 3\nmove 1 from 6 to 1\nmove 5 from 3 to 4\nmove 2 from 8 to 5\nmove 1 from 3 to 6\nmove 1 from 6 to 2\nmove 1 from 2 to 8\nmove 6 from 4 to 2\nmove 1 from 2 to 7\nmove 1 from 5 to 3\nmove 4 from 9 to 3\nmove 1 from 9 to 1\nmove 3 from 1 to 6\nmove 1 from 9 to 7\nmove 14 from 7 to 6\nmove 1 from 8 to 3\nmove 4 from 2 to 6\nmove 3 from 3 to 8\nmove 9 from 4 to 9\nmove 1 from 1 to 5\nmove 2 from 5 to 8\nmove 3 from 8 to 2\nmove 4 from 2 to 6\nmove 1 from 3 to 9\nmove 10 from 6 to 1\nmove 5 from 9 to 8\nmove 1 from 9 to 3\nmove 6 from 1 to 8\nmove 3 from 7 to 4\nmove 2 from 4 to 5\nmove 2 from 9 to 8\nmove 15 from 8 to 3\nmove 3 from 7 to 9\nmove 8 from 4 to 3\nmove 2 from 5 to 9\nmove 6 from 6 to 5\nmove 6 from 5 to 8\nmove 1 from 7 to 8\nmove 6 from 9 to 2\nmove 5 from 2 to 4\nmove 6 from 3 to 5\nmove 5 from 5 to 8\nmove 1 from 5 to 7\nmove 1 from 9 to 7\nmove 2 from 6 to 4\nmove 12 from 8 to 2\nmove 7 from 2 to 4\nmove 3 from 7 to 5\nmove 3 from 5 to 7\nmove 3 from 7 to 9\nmove 2 from 9 to 7\nmove 1 from 9 to 3\nmove 2 from 7 to 4\nmove 3 from 1 to 9\nmove 4 from 6 to 5\nmove 6 from 2 to 8\nmove 14 from 4 to 9\nmove 7 from 9 to 6\nmove 9 from 9 to 2\nmove 1 from 5 to 8\nmove 5 from 6 to 3\nmove 3 from 1 to 9\nmove 3 from 8 to 9\nmove 1 from 8 to 3\nmove 5 from 2 to 5\nmove 1 from 4 to 9\nmove 2 from 6 to 1\nmove 2 from 3 to 6\nmove 3 from 8 to 3\nmove 2 from 6 to 3\nmove 1 from 4 to 9\nmove 4 from 3 to 6\nmove 7 from 6 to 9\nmove 10 from 9 to 2\nmove 10 from 3 to 2\nmove 7 from 2 to 8\nmove 2 from 1 to 7\nmove 13 from 3 to 7\nmove 7 from 5 to 1\nmove 1 from 9 to 6\nmove 4 from 8 to 4\nmove 2 from 3 to 2\nmove 4 from 4 to 6\nmove 1 from 3 to 4\nmove 5 from 6 to 5\nmove 3 from 5 to 7\nmove 12 from 2 to 5\nmove 7 from 5 to 6\nmove 2 from 8 to 3\nmove 7 from 6 to 2\nmove 3 from 9 to 6\nmove 1 from 6 to 7\nmove 1 from 4 to 9\nmove 2 from 7 to 6\nmove 13 from 7 to 4\nmove 3 from 7 to 5\nmove 1 from 9 to 6\nmove 12 from 4 to 3\nmove 1 from 8 to 1\nmove 2 from 6 to 4\nmove 1 from 7 to 9\nmove 2 from 9 to 8\nmove 12 from 3 to 5\nmove 1 from 8 to 2\nmove 15 from 5 to 6\nmove 2 from 4 to 6\nmove 1 from 9 to 6\nmove 5 from 5 to 4\nmove 4 from 4 to 2\nmove 2 from 1 to 5\nmove 4 from 1 to 5\nmove 1 from 8 to 6\nmove 7 from 5 to 2\nmove 22 from 2 to 3\nmove 9 from 6 to 3\nmove 1 from 1 to 8\nmove 1 from 8 to 7\nmove 23 from 3 to 6\nmove 2 from 2 to 4\nmove 1 from 7 to 8\nmove 1 from 8 to 2\nmove 19 from 6 to 9\nmove 2 from 2 to 4\nmove 4 from 4 to 6\nmove 13 from 6 to 8\nmove 12 from 9 to 1\nmove 2 from 5 to 9\nmove 2 from 4 to 8\nmove 1 from 2 to 7\nmove 1 from 7 to 1\nmove 4 from 6 to 2\nmove 10 from 1 to 9\nmove 1 from 6 to 7\nmove 11 from 8 to 2\nmove 6 from 3 to 6\nmove 1 from 7 to 2\nmove 1 from 1 to 8\nmove 2 from 6 to 7\nmove 7 from 6 to 3\nmove 9 from 3 to 1\nmove 7 from 9 to 6\nmove 1 from 8 to 7\nmove 4 from 2 to 6\nmove 1 from 8 to 3\nmove 6 from 6 to 5\nmove 9 from 9 to 3\nmove 5 from 6 to 1\nmove 1 from 7 to 8\nmove 2 from 8 to 4\nmove 1 from 4 to 2\nmove 1 from 4 to 5\nmove 2 from 5 to 6\nmove 1 from 6 to 9\nmove 9 from 1 to 4\nmove 4 from 4 to 6\nmove 2 from 4 to 7\nmove 7 from 2 to 8\nmove 5 from 6 to 7\nmove 6 from 3 to 8\nmove 8 from 1 to 9\nmove 3 from 5 to 2\nmove 2 from 3 to 9\nmove 3 from 9 to 4\nmove 7 from 2 to 3\nmove 1 from 7 to 2\nmove 1" <> ...
input_day5
|> Day5.puzzle1()
"ZWHVFWQWW"
input_day5
|> Day5.puzzle2()
"HZFZCCWWV"

Day6

defmodule Day6 do
  @packet_size 4
  @message_size 14

  def is_start?(chunk, size) do
    chunk |> MapSet.new() |> MapSet.size() == size
  end

  def find_marker(input, size) do
    input
    |> String.to_charlist()
    |> Enum.chunk_every(size, 1)
    |> Enum.with_index(size)
    |> Enum.map(fn {chunk, idx} ->
      {
        is_start?(chunk, size),
        idx
      }
    end)
    |> Enum.find_value(fn {is_start, idx} -> if is_start == true, do: idx end)
  end

  def find_packet_marker(input) do
    find_marker(input, @packet_size)
  end

  def find_message_marker(input) do
    find_marker(input, @message_size)
  end
end
{:module, Day6, <<70, 79, 82, 49, 0, 0, 11, ...>>, {:find_message_marker, 1}}
defmodule Day6Test do
  use ExUnit.Case, async: false
  use ExUnit.Parameterized

  describe "Day6 part1" do
    test_with_params "find packet start marker",
                     fn input, output ->
                       assert Day6.find_packet_marker(input) == output
                     end do
      [
        {"bvwbjplbgvbhsrlpgdmjqwftvncz", 5},
        {"nppdvjthqldpwncqszvftbrmjlhg", 6},
        {"nznrnfrfntjfmvfwmzdfjlvtqnbhcprsg", 10},
        {"zcfzfwzzqfrljwzlrfnpqdbhtmscgvjw", 11}
      ]
    end
  end

  describe "Day6 part2" do
    test_with_params "find message start marker",
                     fn input, output ->
                       assert Day6.find_message_marker(input) == output
                     end do
      [
        {"mjqjpqmgbljsphdztnvjfqwrcgsmlb", 19},
        {"bvwbjplbgvbhsrlpgdmjqwftvncz", 23},
        {"nppdvjthqldpwncqszvftbrmjlhg", 23},
        {"nznrnfrfntjfmvfwmzdfjlvtqnbhcprsg", 29},
        {"zcfzfwzzqfrljwzlrfnpqdbhtmscgvjw", 26}
      ]
    end
  end
end
{:module, Day6Test, <<70, 79, 82, 49, 0, 0, 24, ...>>,
 [
   "test Day6 part2 'find message start marker': number of 0": 1,
   "test Day6 part2 'find message start marker': number of 1": 1,
   "test Day6 part2 'find message start marker': number of 2": 1,
   "test Day6 part2 'find message start marker': number of 3": 1,
   "test Day6 part2 'find message start marker': number of 4": 1
 ]}
ExUnit.run()
.........
Finished in 0.00 seconds (0.00s async, 0.00s sync)
9 tests, 0 failures

Randomized with seed 627574
%{excluded: 0, failures: 0, skipped: 0, total: 9}
input_day6 = File.read!("/Users/akode/dev/advent_of_code/aoc2022/day6.txt")
"pnnfhnhshrhmhwwmwzmznmnwmwfmfhfjfcjjtgtbggpdgdjjbjrjsjpjrrmddmgmpmddrhddnfnfzfpfvpfpprhhlffmtffqhhdtdcdsswsdwswmmfvvpdprrnnhhhtffnfbbznbznnvdnnbffjrfrbfrbrgbrrntnggrqqwtqwwgjgsswgwqwtwwsvwvbwvwrwlrlppzfzwfzzpmzzhqqzqlzlglzzmrmwrmwwvmwvvnppjfjttlffhjjjsccbggnffqgfgjjnccmdmzmllvnlnznttlvlttvnvgnvvqvmvqqzrqqcgglzzwtztwwmjmzjjnddsffqrqlrrvsvdvldvvlgvlvccdzczcqcpphggtnthhhtbhtttcjtjcjgcjcbbrhbbfrffgjgdgzddcttczzsccbpcpddcpcggmjgjddtcccthccfrccmdmhmddnwddfldffntnptnpttcptcptpfphhmfmwfwmmlblgbgvbvlltqltldttfcfcclgcllmplmlbbjnjzjnzzttnvvgddshddsqddggsqgqddsggdhghjgjhhgchhdmdjmjddgdhghrrphrrpnnqhhjwwqrrcmmslmmszzpgzpzzrmzmznzllnjnnlnbbdvdsdffbpffcmmnznqqcbbzvvjnjvvwqwgqqpnnzwnzwnzwwwlpwpzzfqzfqqwnqnbnfnqnbqqbggqnqdndrrzzlffbbgqgfgrfrqqsddnqnqjjgssqwqwcqcpcrrqppwpjjfnfpffhphwwmcwwznwznnplptlplnlsnlsldslslsffwtwftwtbtdbbjsjcczwwfllwtlwtlwlvwlwrwppsggvcvrrqcrqqvmqvmmbrrsbsfspspjpnnmpmqmcczgzffqmfmtmpppwzppzrpzrzsrrpqrpqpmpvmpvpttbqtqmtmjttqdqgggcppclcjcpcsppctpplpdpcppcmmdzmzddvhvhnhrrldllcwwbnwnssshlhrhthggtmggbjbjwwbvbttjllvrrfggngvngnmmvzzrrmddmcddztztctfccqpcpcqqvqppqcqdcdhhvhssgfgzgwwzmmnssvwwbqbhbnhnphpqqjcqcddfwfttqjtqtlttglljgjbgjgnnsqqvrvffqvqfqbffljjpffssqdsqstqqqldqqmhmsmsqqwtqwqdqgdgjjfbjffgbbrhhqghgppqgpgmpmmfzfhhfrhffgmfggpzgpzzhtzhhlbhhqbbzvvnvqnntptmmbhbdhdwwmjjcnnmsscqcbbtjtvjvwjvvmsmjmtmpmgghttcztzggpddbfbfgbbdsdrsrrqfqjjqfjjhzhtzzmdzzcgzgdzzmvmmfmjmgjmggmppbdppmzpppvfppzhhfsfwfhhpjpmmrjjpssdccjpjpwjppvdpphcpcjcfjfwjfwfjwfjjqcqcwqqqsmmmbbgdgwwpcwwdfdlflrltlgtthfhfjhhlthtddlgdggsjsrrdpdcppgttphpgpwppmpzmmrjmmvjvgvgfglfgllbqlqhllszzlwwhzzdfdcdtctptwtztfzzmjzjtjtrjrcrnrjjmwmnnbddgvgtgsstjsszmpqdmzgqflrbrspjmtzjcrmlzltmhgblghnwqvwwqwzbpnfrpdpblpjgshfccfbjfsnwvvhnjftsdnsgtzzjtzpmtfdvzrhtqpblhwgmqtgpbfvbdmsnrrrvvbstpsznvbbwgjfqjrhdvwvgptpglpfddhddmtglmjlpwlvfpbtbmgbplbzrlpdlvqzcwhbscpszgfstjpfdvfpmljlngrbgrdnnblzqrfpzsdvblpwbtnhdjclldvwvbwcwzfzbdspgwpfqjfbdbrqcshtlvcrdstnzggbwqnzbrfzbpnrtmvpbvdhcvdsdshgtvhfgdzljflppqbwclnvbhbczvrscjhlbgbfvwdjhnjsgmvwhpfgwbbmnndpnglfrmtfdzvqgfjdqfhgrhvpbqndmqnqccgwswwdsqjnbjtjbjdbqgjnmfbdvlnfwbnrdqgvgzzhmmbbdzfdvvpwhpbwbnzdcdpchrwlhfsjnhhjggvplmqggwjdsvjtpnpnqgldjjdcscrdltssjdrpcrfbgbcjfplhzgwbprfcslhpcngtszrghmwhzdqscbfrhzdwcffzvmjrmcjcstfvhplvrsglgsjnjtrpddsdfqjsndjnfmvdhfgdbzzflqhsrrwmrnlpqzmcddqbqvvzgtlztpgjnddtcnbmqsjlhmcszrmcjvwzpptlfqsmpvgnzvrjdwzpdwqgbmdgdtvjlmfczthjbcgfhbqpnmlbmrwwhfptzlbmfdhssznjcvjbmnjtnvzjhzczlrrdnttmmcbnzhqpplzqwgttwrnwfvmnptgqlfrnzvqpjfgrzwmlcwvtptvcvrlsrdwdgqfvffspmdbnnrqjttpqvhvdpbcrvzptwnhhfsqzchmncvttcdgdnlppcfzpmjpvbvqhlvplwvrmmbbggbwttwmvsqjlllsftprsmtmnzjcqfzblrllzgshfljchrjwjlpvhpbrtrsschzltrblgjnbgdnmwdggjhqggntblnhsvfgsbcblhmctbqzqwmhqnjhpzjfqpjdgwpzhczcftfcpdhvzhzccmwmrfrbqshzmtpqgpbbvfqqbjbmvnlnlwjtzrpmhdlffccrqcfgsjfszbrzrfztntchtmgmbhjgmlsqzcbtqqjzzlghtzzqmlnnvsgsvbbjfgqsqbqmqrdzwpwdgbggpdvhvnlzshhntprjdwhnwfvdjzpqgflwrvwgtmfdmfdztcbtfnjdrvgdwwczdgphnvdgrbdchprqldfjrvcsflcmlcmzqvqgsgnzcgmrhccgcmptcdzhbcdgdtppwztfstzqqzqrdzlnzthggjmpcflmbcmdrrjnnpbpqfmjbzqbtsjjgdlmgncbmgspqqvbrvzrdjscpzjsdtcdvsdwqlmwrngttswnrsbqctvhgfnnwblpcqzdmzpfchplslspmghvgcqntmlrfhgpcbpspvfhnvqvglsqzsnsdzddqpbsjhlclslngbwvvgjhwfcncqsmqwbptzvpzlzslsjjjldjpwpfrdlfbjphqcjtsgqdsdfdjhqgdhcppndwmhmmldvvmblcqcqfqhltbcbvrnghjfmtgqwtwljtczvqlnmgscjhqdhnzwhzvzzqnlsrhqvljqpgpwghfqlhjjrrhvnmnnrbnlhdcjctwtlhmhhmhjvcgzdrzmdjrvqzgnsttjdwglgwlcmbcdnjprgfsbbdzzngbqdrvwwwhbtlnnmzqdjttsrrpvlfdqnfhhtdtvmpcjgdwtbnqmwmtszdqfmbhjsjpqqddzfggwjhbtlnqfgcwbjzdtcpcpzgnrmnvwlpgmwfjlpgppdfrfvvjwsfcdqdnpcpjbqsvhttssgptqjghctrbgntlfjzdrfjccsprsjlrrwrzsmnjsqslmpdtrvhlqbnmgpjthpqdqmnvrtzlhhzzfzbrcclpmpcszhbttgrtcpgcpjwpdbfpfvgspsgtvglwthqcmcvmrfmclwlvjlsptfgmtlrnsvjrnfwzhdcsmgztpzfcvzwdztpppvqpvqfpdrsfnlhrbqwrsqjtwjmhnpwmqmpdgdhbtbpfwnmswffdqffdggrdrpmngvpzplmmwlddnhcvjjzqqfsbbtfmzdwnpvbjrshmllczhgvwwcbcbtfrfnplqjwmjlvpwwgfrtffwddwppsgtnlmpvfnhfzcsgjbqbjmbvpnqppsrvwnlzvcmjqgtbzrdsnrgwbfmrvnflgccrssfvcwgllqqbbcthzmbtnsmbzbcczhtzcvmthttpltrtdmgspctvtpvqbhmnnpnjwmhpqclmjsdrbjwvjbtzcjlqbjsvbgdwqzflnwzcfjwtrhjgfshfmwbjfwpnhjsmtpgbpwlfjjnmdlrhchmnfmgmgcrftmwbzshdwbhndgwtjbrrvbwprqppfmgfmfllpcjgrwdmtzddthsjlgjljv\n"
Day6.find_packet_marker(input_day6)
1623
Day6.find_message_marker(input_day6)
3774