|
|
@ -13,89 +13,44 @@ defmodule Day22 do
|
|
|
|
|
|
|
|
|
|
|
|
dbg(part1)
|
|
|
|
dbg(part1)
|
|
|
|
|
|
|
|
|
|
|
|
# lines = [123, 123]
|
|
|
|
# build a map of all 4-digit sequences + list index to prices
|
|
|
|
|
|
|
|
map =
|
|
|
|
{prices, diffs} =
|
|
|
|
Enum.with_index(lines)
|
|
|
|
Enum.reduce(lines, {[], []}, fn secret, {prices_acc, diffs_acc} ->
|
|
|
|
|> Enum.reduce(%{}, fn {secret, idx}, map ->
|
|
|
|
{_, prices, diffs} =
|
|
|
|
{_, prices, diffs, map2} =
|
|
|
|
Enum.reduce(1..2000, {secret, [price(secret)], []}, fn _, {s, prices, diffs} ->
|
|
|
|
Enum.reduce(1..2000, {secret, [price(secret)], [], map}, fn _, {s, prices, diffs, m} ->
|
|
|
|
new_secret = evolve(s)
|
|
|
|
new_secret = evolve(s)
|
|
|
|
price = price(new_secret)
|
|
|
|
price = price(new_secret)
|
|
|
|
diff = price - hd(prices)
|
|
|
|
diff = price - hd(prices)
|
|
|
|
{new_secret, [price | prices], [diff | diffs]}
|
|
|
|
new_diff = [diff | diffs]
|
|
|
|
|
|
|
|
sec = Enum.slice(new_diff, 0, 4)
|
|
|
|
|
|
|
|
new_map = Map.put_new(m, {sec, idx}, price)
|
|
|
|
|
|
|
|
{new_secret, [price | prices], new_diff, new_map}
|
|
|
|
end)
|
|
|
|
end)
|
|
|
|
|
|
|
|
|
|
|
|
{[prices | prices_acc], [diffs | diffs_acc]}
|
|
|
|
map2
|
|
|
|
end)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
dbg({prices, diffs})
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# max length of all price lists
|
|
|
|
|
|
|
|
max = Enum.map(prices, &length/1) |> Enum.max()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 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)
|
|
|
|
end)
|
|
|
|
|> Enum.with_index()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# dbg(sorted_by_price_with_index)
|
|
|
|
# for every possible sequence (there's only like 19 ^ 4 or something)
|
|
|
|
|
|
|
|
all = for a <- -9..9, b <- -9..9, c <- -9..9, d <- -9..9, do: [a, b, c, d]
|
|
|
|
|
|
|
|
|
|
|
|
# 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 =
|
|
|
|
part2 =
|
|
|
|
Enum.reduce(0..(max - 1), 0, fn index, acc ->
|
|
|
|
Enum.reduce(all, {0, []}, fn sec, {max, max_sec} ->
|
|
|
|
dbg({"checking all lists at index", index})
|
|
|
|
# and for every buyer, get the price at this sequence
|
|
|
|
dbg({"current acc", acc})
|
|
|
|
val =
|
|
|
|
|
|
|
|
Enum.reduce(0..length(lines), 0, fn idx, acc ->
|
|
|
|
res =
|
|
|
|
case Map.get(map, {sec, idx}, nil) do
|
|
|
|
Enum.reduce(sorted_by_price_with_index, {0, []}, fn {price_list, list_index},
|
|
|
|
nil -> acc
|
|
|
|
{max_price, max_seq} ->
|
|
|
|
val -> val + acc
|
|
|
|
{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
|
|
|
|
end)
|
|
|
|
end)
|
|
|
|
|
|
|
|
|
|
|
|
if res > acc do
|
|
|
|
if val > max, do: {val, sec}, else: {max, max_sec}
|
|
|
|
dbg({"new high", res})
|
|
|
|
|
|
|
|
res
|
|
|
|
|
|
|
|
else
|
|
|
|
|
|
|
|
acc
|
|
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
end)
|
|
|
|
end)
|
|
|
|
|
|
|
|
|
|
|
|
dbg(part2)
|
|
|
|
dbg(part2)
|
|
|
|
end
|
|
|
|
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
|
|
|
|
defp evolve(secret) do
|
|
|
|
step1 = secret |> Kernel.*(64) |> mix(secret) |> prune()
|
|
|
|
step1 = secret |> Kernel.*(64) |> mix(secret) |> prune()
|
|
|
|
step2 = step1 |> div(32) |> mix(step1) |> prune()
|
|
|
|
step2 = step1 |> div(32) |> mix(step1) |> prune()
|
|
|
@ -113,15 +68,6 @@ defmodule Day22 do
|
|
|
|
defp price(num) do
|
|
|
|
defp price(num) do
|
|
|
|
Integer.digits(num) |> Enum.take(-1) |> Integer.undigits()
|
|
|
|
Integer.digits(num) |> Enum.take(-1) |> Integer.undigits()
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
# finds the index of a sequence in a list, nil if it isn't in there
|
|
|
|
|
|
|
|
defp index_of_sublist(parent, sublist) do
|
|
|
|
|
|
|
|
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
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
Day22.run()
|
|
|
|
Day22.run()
|
|
|
|