this repo has no description
at master 3.5 kB view raw
1<!-- vim:ft=markdown --> 2 3<!-- livebook:{"persist_outputs":true} --> 4 5# Day 23 6 7## Section 8 9```elixir 10input = 11 File.stream!("day23.txt") 12 |> Enum.map(fn line -> 13 for <<c <- line>>, c in 'ABCD', do: String.to_atom(<<c + 32>>) 14 end) 15 |> Enum.reject(&(&1 == [])) 16 |> Enum.zip() 17 |> Enum.map(&Tuple.to_list/1) 18 |> Enum.zip_with(~w[a b c d]a, &{&2, &1}) 19 |> Map.new() 20``` 21 22<!-- livebook:{"output":true} --> 23 24``` 25%{a: [:d, :b], b: [:d, :a], c: [:c, :b], d: [:c, :a]} 26``` 27 28Graph of the possible movements. `--` and `|` have multiply 1 and `---`, `\`, and `/` have 29multiply 2. 30 31``` 32.--.---.---.---.---.--. 33 \ / \ / \ / \ / 34 . . . . 35 | | | | 36 . . . . 37``` 38 39```elixir 40defmodule Day23 do 41 @costs %{a: 1, b: 10, c: 100, d: 1000} 42 @rooms %{a: -3, b: -1, c: 1, d: 3} 43 44 # - - - - - + + + + + 45 # 5 4 3 2 1 0 1 2 3 4 5 46 # A B C D 47 # A B C D 48 49 defp memoize(tid, args, func) do 50 case :ets.lookup(tid, args) do 51 [{^args, value}] -> 52 value 53 54 [] -> 55 value = func.() 56 :ets.insert(tid, {args, value}) 57 value 58 end 59 end 60 61 def process(stacks) do 62 tid = :ets.new(:memoize, [:public, :set]) 63 depth = length(stacks[:a]) 64 65 try do 66 do_process(stacks, %{}, target(depth), depth, tid) 67 after 68 :ets.delete(tid) 69 end 70 end 71 72 defp do_process(target, _, target, _depth, _tid), do: 0 73 74 defp do_process(stacks, hall, target, depth, tid) do 75 memoize(tid, [stacks, hall], fn -> 76 possible_moves(stacks, hall, depth) 77 |> Enum.map(fn {new_stack, new_hall, cost} -> 78 cost + do_process(new_stack, new_hall, target, depth, tid) 79 end) 80 |> Enum.min(&<=/2, fn -> :inf end) 81 end) 82 end 83 84 defp possible_moves(stacks, hall, depth) do 85 hall_to_room(stacks, hall, depth) ++ room_to_hall(stacks, hall, depth) 86 end 87 88 defp hall_to_room(stacks, hall, depth) do 89 # IO.inspect({stacks, hall, depth}, label: elem(__ENV__.function, 0)) 90 for {pos, t} <- hall, 91 clear_path_to_room?(t, pos, hall), 92 accepts?(t, stacks), 93 {size, new_stacks} = into_room(t, stacks), 94 do: {new_stacks, Map.delete(hall, pos), cost(t, pos, @rooms[t], depth - size)} 95 end 96 97 defp room_to_hall(stacks, hall, depth) do 98 [] 99 end 100 101 defp clear_path_to_room?(t, pos, hall) do 102 hall 103 |> Map.keys() 104 |> Enum.find(&(&1 in min(pos, @rooms[t])..max(pos, @rooms[t]))) 105 |> case do 106 nil -> true 107 _ -> false 108 end 109 end 110 111 defp accepts?(t, stacks), do: Enum.all?(stacks[t], &(&1 == t)) 112 113 defp into_room(t, stacks) do 114 Map.get_and_update!(stacks, t, &{length(&1), [t | &1]}) 115 end 116 117 defp target(depth) do 118 for v <- ~w[a b c d]a, 119 into: %{}, 120 do: {v, List.duplicate(v, depth)} 121 end 122 123 def cost(elem, from, to, depth) do 124 @costs[elem] * (depth + abs(to - from)) 125 end 126end 127``` 128 129<!-- livebook:{"output":true} --> 130 131``` 132warning: variable "depth" is unused (if the variable is not meant to be used, prefix it with an underscore) 133 day23.livemd#cell:58: Day23.room_to_hall/3 134 135warning: variable "hall" is unused (if the variable is not meant to be used, prefix it with an underscore) 136 day23.livemd#cell:58: Day23.room_to_hall/3 137 138warning: variable "stacks" is unused (if the variable is not meant to be used, prefix it with an underscore) 139 day23.livemd#cell:58: Day23.room_to_hall/3 140 141``` 142 143<!-- livebook:{"output":true} --> 144 145``` 146{:module, Day23, <<70, 79, 82, 49, 0, 0, 23, ...>>, {:cost, 4}} 147``` 148 149```elixir 150Day23.process(input) 151``` 152 153<!-- livebook:{"output":true} --> 154 155``` 156:inf 157```