diff --git a/day22/main.exs b/day22/main.exs index 41cd0e9..b111b4d 100644 --- a/day22/main.exs +++ b/day22/main.exs @@ -1,7 +1,7 @@ defmodule Day22 do def run do lines = - File.read!("test.txt") + File.read!("data.txt") |> String.trim() |> String.split("\n") |> Enum.map(&String.to_integer/1) @@ -28,70 +28,74 @@ defmodule Day22 do {[prices | prices_acc], [diffs | diffs_acc]} end) - dbg(prices) - dbg(diffs) + dbg({prices, diffs}) - concatted_diffs = Enum.concat(diffs) + # max length of all price lists + max = Enum.map(prices, &length/1) |> Enum.max() - # iterate over ALL 4 diff sequences among all the numbers - part2 = - concatted_diffs + # sort the lists by price, keeping their original index + sorted_by_price_with_index = + Enum.map(prices, fn prices -> + prices |> Enum.with_index() |> Enum.sort(fn {p1, _}, {p2, _} -> p1 >= p2 end) + end) |> Enum.with_index() - |> Enum.reduce({0, []}, fn {d, idx}, {max, best_seq} -> - seq = Enum.slice(concatted_diffs, idx, 4) - # dbg({d, idx, seq}) - - if length(seq) == 4 do - # find the index of this 4 diff sequence in all the diff lists - total = - Enum.with_index(diffs) - |> Enum.reduce(0, fn {diff_list, list_idx}, acc -> - i = index_of_sublist(diff_list, seq) - # dbg({"looking for sublist", seq, i}) - - if Enum.reverse(seq) == [-2, 1, -1, 3] do - dbg("found seq") - dbg(seq) - dbg({"checking diff list for this seq", i}) - end - - # if this seq exists in this diff list, find the corresponding price - if !is_nil(i) do - # dbg(list_idx) - # dbg(prices) - price_list = Enum.at(prices, list_idx) - # dbg(price_list) - price = Enum.at(price_list, i) - - if Enum.reverse(seq) == [-2, 1, -1, 3] do - dbg({"price", price}) - end - - # dbg({"found the seq. price", price}) - acc + price - else - acc - end - end) - - if Enum.reverse(seq) == [-2, 1, -1, 3] do - dbg({"total total", total}) - end - - if total >= max do - dbg({"new winner", total, seq}) - {total, seq} - else - {max, best_seq} - end + + # dbg(sorted_by_price_with_index) + + # go from 0 up to the max list length of the lists sorted by price, highest to lowest + # grab the 4-sequence of each list + # check each sequence against each list, add up the prices + # if that price is greater than the max acc price, that's the new winning sequence + part2 = + Enum.reduce(0..(max - 1), 0, fn index, acc -> + dbg({"checking all lists at index", index}) + dbg({"current acc", acc}) + + res = + Enum.reduce(sorted_by_price_with_index, {0, []}, fn {price_list, list_index}, + {max_price, max_seq} -> + {price, original_index} = Enum.at(price_list, index) + # dbg({diffs, index}) + seq = Enum.at(diffs, list_index) |> Enum.slice(original_index, 4) + # dbg({price, seq}) + + if length(seq) == 4 do + max_price = score_seq(prices, diffs, seq) + # dbg({"max_price", max_price}) + + {max_price, seq} + else + {max_price, max_seq} + end + end) + + if res > acc do + dbg({"new high", res}) + res else - {max, best_seq} + acc end end) dbg(part2) end + defp score_seq(prices, diffs, seq) do + # dbg({"score seq", seq}) + + res = + Enum.zip(prices, diffs) + |> Enum.reduce(0, fn {p, d}, acc -> + case index_of_sublist(d, seq) do + nil -> acc + idx -> Enum.at(p, idx) + acc + end + end) + + res + # dbg(res) + end + defp evolve(secret) do step1 = secret |> Kernel.*(64) |> mix(secret) |> prune() step2 = step1 |> div(32) |> mix(step1) |> prune() @@ -112,18 +116,10 @@ defmodule Day22 do # finds the index of a sequence in a list, nil if it isn't in there defp index_of_sublist(parent, sublist) do - sub_len = length(sublist) - - Enum.reduce(0..(length(parent) - sub_len), nil, fn idx, acc -> - if acc do - acc - else - slice = Enum.slice(parent, idx, sub_len) - - if slice == sublist do - idx - end - end + Enum.reduce_while(0..(length(parent) - length(sublist)), nil, fn idx, acc -> + if Enum.slice(parent, idx, length(sublist)) == sublist, + do: {:halt, idx}, + else: {:cont, acc} end) end end