add day 12a and day 18a

This commit is contained in:
Pim Kunis 2023-12-19 08:22:20 +01:00
parent 092bb05312
commit d20bb3f539
6 changed files with 1851 additions and 0 deletions

103
23/elixir/lib/days/day12.ex Normal file
View file

@ -0,0 +1,103 @@
defmodule AOC.Day12 do
use AOC.Day, day: 12, input: "example"
# use AOC.Day, day: 12
def parse_input(lines) do
Enum.map(lines, fn line ->
[conditions, groups] = String.split(line, " ")
conditions = String.to_charlist(conditions)
groups =
groups
|> String.split(",")
|> Enum.map(&String.to_integer/1)
{conditions, groups}
end)
end
def possible_unknown_spring_conditions(unknown_spring_count) when unknown_spring_count == 0,
do: [[]]
def possible_unknown_spring_conditions(unknown_spring_count) do
next_list = possible_unknown_spring_conditions(unknown_spring_count - 1)
Enum.map(next_list, &[true | &1]) ++ Enum.map(next_list, &[false | &1])
end
def apply_spring_configuration([], []), do: []
def apply_spring_configuration([?. | conditions], spring_configuration) do
[?. | apply_spring_configuration(conditions, spring_configuration)]
end
def apply_spring_configuration([?# | conditions], spring_configuration) do
[?# | apply_spring_configuration(conditions, spring_configuration)]
end
def apply_spring_configuration([?? | conditions], [true | spring_configuration]) do
[?. | apply_spring_configuration(conditions, spring_configuration)]
end
def apply_spring_configuration([?? | conditions], [false | spring_configuration]) do
[?# | apply_spring_configuration(conditions, spring_configuration)]
end
def valid_spring_conditions?(conditions, []) do
not Enum.member?(conditions, ?#)
end
def valid_spring_conditions?([?. | conditions], groups) do
valid_spring_conditions?(conditions, groups)
end
def valid_spring_conditions?(conditions, [count | groups]) do
{left, right} = Enum.split(conditions, count)
length(left) == count and Enum.all?(left, &(&1 == ?#)) and
(length(right) == 0 or hd(right) == ?.) and valid_spring_conditions?(right, groups)
end
def generate_arrangements(conditions, groups) do
unknown_spring_count = Enum.count(conditions, &(&1 == ??))
possible_unknown_spring_conditions(unknown_spring_count)
|> Stream.map(fn spring_configuration ->
apply_spring_configuration(conditions, spring_configuration)
end)
|> Stream.filter(fn possible_conditions ->
valid_spring_conditions?(possible_conditions, groups)
end)
# |> Enum.to_list()
end
def calculate_arrangement_counts(input, duplicates \\ 1) do
input
|> Enum.map(fn {conditions, groups} ->
conditions =
conditions
|> List.duplicate(duplicates)
|> Enum.intersperse(~c"?")
|> List.flatten()
groups =
groups
|> List.duplicate(duplicates)
|> List.flatten()
generate_arrangements(conditions, groups)
end)
|> Enum.map(&Enum.count/1)
|> Enum.sum()
end
def part1(input) do
calculate_arrangement_counts(input)
end
def part2(input) do
calculate_arrangement_counts(input, 5)
end
end
# NOTE TO SELF: memoize the brute force...

110
23/elixir/lib/days/day18.ex Normal file
View file

@ -0,0 +1,110 @@
defmodule AOC.Day18 do
# use AOC.Day, day: 18, input: "example"
use AOC.Day, day: 18
def parse_input(lines) do
Enum.map(lines, fn line ->
%{"direction" => direction, "length" => length, "color" => color} =
Regex.named_captures(
~r/^(?<direction>[UDLR]) (?<length>\d+) \(\#(?<color>[[:alnum:]]+)\)$/,
line
)
{String.to_atom(direction), String.to_integer(length), color}
end)
end
def dig_stretch({y, x}, direction, length) do
Enum.map(1..length, fn n ->
case direction do
:U -> {y - n, x}
:R -> {y, x + n}
:D -> {y + n, x}
:L -> {y, x - n}
end
end)
end
def execute_dig_plan(dig_plan) do
Enum.reduce(dig_plan, {%{{0, 0} => true}, {0, 0}}, fn {direction, length, _color},
{terrain, position} ->
stretch = dig_stretch(position, direction, length)
terrain =
Enum.reduce(stretch, terrain, fn new_position, acc ->
Map.put(acc, new_position, true)
end)
new_position = stretch |> Enum.reverse() |> hd()
{terrain, new_position}
end)
end
def print_terrain(terrain) do
max_y = terrain |> Enum.map(&elem(&1, 0)) |> Enum.map(&elem(&1, 0)) |> Enum.max()
max_x = terrain |> Enum.map(&elem(&1, 0)) |> Enum.map(&elem(&1, 1)) |> Enum.max()
min_y = terrain |> Enum.map(&elem(&1, 0)) |> Enum.map(&elem(&1, 0)) |> Enum.min()
min_x = terrain |> Enum.map(&elem(&1, 0)) |> Enum.map(&elem(&1, 1)) |> Enum.min()
Enum.each(min_y..max_y, fn y ->
Enum.map(min_x..max_x, fn x ->
case Map.fetch(terrain, {y, x}) do
:error -> "."
_ -> "#"
end
end)
|> Enum.join()
|> IO.puts()
end)
end
def find_interior_space(terrain) do
max_x = terrain |> Enum.map(&elem(&1, 0)) |> Enum.map(&elem(&1, 1)) |> Enum.max()
min_x = terrain |> Enum.map(&elem(&1, 0)) |> Enum.map(&elem(&1, 1)) |> Enum.min()
edge_x =
Enum.find(min_x..max_x, fn x ->
case Map.fetch(terrain, {2, x}) do
:error -> false
_ -> true
end
end)
edge_x + 1
end
def flood_fill_terrain(terrain) do
interior_x = find_interior_space(terrain)
flood_fill_terrain(terrain, {1, interior_x})
end
def flood_fill_terrain(terrain, {y, x}) do
[{y - 1, x}, {y, x + 1}, {y + 1, x}, {y, x - 1}]
|> Enum.reduce(terrain, fn next_position, acc ->
case Map.fetch(acc, next_position) do
:error ->
acc
|> Map.put(next_position, true)
|> flood_fill_terrain(next_position)
_ ->
acc
end
end)
end
def part1(dig_plan) do
execute_dig_plan(dig_plan)
|> elem(0)
# |> tap(&print_terrain/1)
|> flood_fill_terrain()
# |> tap(&print_terrain/1)
|> Enum.count()
end
def part2(_input) do
"TODO"
end
end