From c735ab61c7d3af7b91ace22d41e4c3467f0cff2f Mon Sep 17 00:00:00 2001 From: Doruk Gurleyen Date: Sun, 12 Dec 2021 01:38:16 -0600 Subject: [PATCH] 2021.12 --- challenges/2021/12.exs | 72 +++++++++++++++++++++++++++++++++++ challenges/2021/12.js | 61 +++++++++++++++++++++++++++++ challenges/2021/inputs/12.txt | 23 +++++++++++ 3 files changed, 156 insertions(+) create mode 100644 challenges/2021/12.exs create mode 100644 challenges/2021/12.js create mode 100644 challenges/2021/inputs/12.txt diff --git a/challenges/2021/12.exs b/challenges/2021/12.exs new file mode 100644 index 0000000..e2a821b --- /dev/null +++ b/challenges/2021/12.exs @@ -0,0 +1,72 @@ +Code.compile_file(Path.join([__ENV__.file], ["../../../utils/utils.exs"])) + +defmodule Challenge do + @moduledoc false + + def first_result(input) do + input + |> parse_input + |> build_cave_states + |> explore("start") + end + + def second_result(input) do + input + |> parse_input + |> build_cave_states + |> explore("start", 2) + end + + defp explore(states, cave, max_sm_cave_visits \\ 1, seen_sm_cave \\ false) + defp explore(_states, "end", _max_sm_cave_visits, _seen_sm_cave), do: 1 + + defp explore(states, cave, max_sm_cave_visits, seen_sm_cave) do + {adjacencies, visited} = Map.get(states, cave) + + cave + |> updated_visited_count(visited, seen_sm_cave, max_sm_cave_visits) + |> case do + nil -> + 0 + + new_visited_count -> + updated_states = Map.put(states, cave, {adjacencies, new_visited_count}) + + Enum.reduce( + adjacencies, + 0, + &(&2 + explore(updated_states, &1, max_sm_cave_visits, seen_sm_cave || visited > 0)) + ) + end + end + + defp updated_visited_count(cave, seen_count, seen_sm_cave, max_sm_cave_visits \\ 1) + defp updated_visited_count(_cave, 1, _, 1), do: nil + defp updated_visited_count(_cave, 2, _seen_sm_cave, 2), do: nil + defp updated_visited_count(_cave, 1, true, 2), do: nil + + defp updated_visited_count(cave, seen_count, _seen_sm_cave, _max_sm_cave_visits), + do: if(String.downcase(cave) == cave, do: seen_count + 1, else: 0) + + defp build_cave_states(adjacencies) do + Enum.reduce(adjacencies, %{}, fn [left, right], acc -> + left_state = Map.get(acc, left, {[], 0}) + right_state = Map.get(acc, right, {[], 0}) + + updated_left_state = maybe_add_to_adjacencies(right, left_state) + updated_right_state = maybe_add_to_adjacencies(left, right_state) + + acc + |> Map.put(left, updated_left_state) + |> Map.put(right, updated_right_state) + end) + end + + defp maybe_add_to_adjacencies("start", state), do: state + defp maybe_add_to_adjacencies(cave, state), do: {[cave | elem(state, 0)], elem(state, 1)} + + defp parse_input(input), do: Enum.map(input, &String.split(&1, "-")) +end + +Utils.run(&Challenge.first_result/1, __ENV__.file, "Q1") +Utils.run(&Challenge.second_result/1, __ENV__.file, "Q2") diff --git a/challenges/2021/12.js b/challenges/2021/12.js new file mode 100644 index 0000000..11d325c --- /dev/null +++ b/challenges/2021/12.js @@ -0,0 +1,61 @@ +// Part 1 +const solvePuzzle1 = (input) => { + const caveStates = buildCaveStates(parseInput(input)); + const getIncrementVisitedBy = (cave, visited) => { + if (visited) return null; + if (cave.toLowerCase() === cave) return 1; + return 0; + }; + return explore("start", caveStates, getIncrementVisitedBy); +}; + +// Part 2 +const solvePuzzle2 = (input) => { + const caveStates = buildCaveStates(parseInput(input)); + const getIncrementVisitedBy = (cave, visitedCount, visitedSmallCave) => { + if (visitedCount === 2 || (visitedCount === 1 && visitedSmallCave)) return null; + if (cave.toLowerCase() === cave) return 1; + return 0; + }; + return explore("start", caveStates, getIncrementVisitedBy); +}; + +const addCaveToAdjacencies = (cave, state) => { + if (!state) return null; + cave !== "start" && state[0].push(cave); + return state; +}; + +const buildCaveStates = (input) => { + const caveStates = new Map(); + for (let [left, right] of input) { + addCaveToAdjacencies(right, caveStates.get(left)) || caveStates.set(left, createCaveState(right)); + addCaveToAdjacencies(left, caveStates.get(right)) || caveStates.set(right, createCaveState(left)); + } + return caveStates; +}; + +const createCaveState = (cave) => (cave !== "start" ? [[cave], 0] : [[], 0]); + +const explore = (cave, caveStates, getIncrementVisitedBy, visitedSmallCave = false) => { + if (cave === "end") return 1; + + const stateOfTheCave = caveStates.get(cave); + const [adjacencies, visited] = stateOfTheCave; + const incrementVisitedBy = getIncrementVisitedBy(cave, visited, visitedSmallCave); + + if (incrementVisitedBy == null) return 0; + stateOfTheCave[1] += incrementVisitedBy; + + const pathsFound = adjacencies.reduce( + (acc, val) => acc + explore(val, caveStates, getIncrementVisitedBy, visitedSmallCave || visited), + 0 + ); + stateOfTheCave[1] -= incrementVisitedBy; + return pathsFound; +}; + +const parseInput = (input) => input.split("\n").map((l) => l.split("-")); + +require(__dirname + "/../../utils/test.js").test(__filename, __dirname, solvePuzzle1); +require(__dirname + "/../../utils/test.js").test(__filename, __dirname, solvePuzzle2); diff --git a/challenges/2021/inputs/12.txt b/challenges/2021/inputs/12.txt new file mode 100644 index 0000000..c9a63b5 --- /dev/null +++ b/challenges/2021/inputs/12.txt @@ -0,0 +1,23 @@ +pn-TY +rp-ka +az-aw +al-IV +pn-co +end-rp +aw-TY +rp-pn +al-rp +end-al +IV-co +end-TM +co-TY +TY-ka +aw-pn +aw-IV +pn-IV +IV-ka +TM-rp +aw-PD +start-IV +start-co +start-pn \ No newline at end of file