aboutsummaryrefslogtreecommitdiff
path: root/aoc2023/build/packages/gap/src/gap.erl
diff options
context:
space:
mode:
authorHJ <thechairman@thechairman.info>2024-02-03 15:09:54 -0500
committerHJ <thechairman@thechairman.info>2024-02-03 15:09:54 -0500
commit96a3c5c179d8d3fff24eb2953e45f8dd15e2714c (patch)
tree0a67bc0cfeabe51740bb049c61f16f1ac3bdd4ff /aoc2023/build/packages/gap/src/gap.erl
parent547fe03cf43105f46160e2dd9afff21637eaaf47 (diff)
downloadgleam_aoc-96a3c5c179d8d3fff24eb2953e45f8dd15e2714c.tar.gz
gleam_aoc-96a3c5c179d8d3fff24eb2953e45f8dd15e2714c.zip
cleanup
Diffstat (limited to 'aoc2023/build/packages/gap/src/gap.erl')
-rw-r--r--aoc2023/build/packages/gap/src/gap.erl538
1 files changed, 538 insertions, 0 deletions
diff --git a/aoc2023/build/packages/gap/src/gap.erl b/aoc2023/build/packages/gap/src/gap.erl
new file mode 100644
index 0000000..827e5ce
--- /dev/null
+++ b/aoc2023/build/packages/gap/src/gap.erl
@@ -0,0 +1,538 @@
+-module(gap).
+-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function]).
+
+-export([to_styled/1, compare_strings_with_algorithm/3, compare_lists_with_algorithm/3, myers/2, compare_lists/2, compare_strings/2, lcs/2]).
+-export_type([score/1]).
+
+-type score(GAM) :: {score, integer(), gleam@option:option(GAM)}.
+
+-spec to_styled(gap@comparison:comparison(any())) -> gap@styled_comparison:styled_comparison().
+to_styled(Comparison) ->
+ _pipe = Comparison,
+ _pipe@1 = gap@styling:from_comparison(_pipe),
+ _pipe@2 = gap@styling:highlight(
+ _pipe@1,
+ fun gap@styling:first_highlight_default/1,
+ fun gap@styling:second_highlight_default/1,
+ fun gap@styling:no_highlight/1
+ ),
+ gap@styling:to_styled_comparison(_pipe@2).
+
+-spec compare_strings_with_algorithm(
+ binary(),
+ binary(),
+ fun((list(binary()), list(binary())) -> gap@comparison:comparison(binary()))
+) -> gap@comparison:comparison(binary()).
+compare_strings_with_algorithm(First, Second, Algorithm) ->
+ Comparison = Algorithm(
+ gleam@string:to_graphemes(First),
+ gleam@string:to_graphemes(Second)
+ ),
+ case Comparison of
+ {list_comparison, First@1, Second@1} ->
+ {string_comparison, First@1, Second@1};
+
+ {string_comparison, First@2, Second@2} ->
+ {string_comparison, First@2, Second@2}
+ end.
+
+-spec compare_lists_with_algorithm(
+ list(GBB),
+ list(GBB),
+ fun((list(GBB), list(GBB)) -> gap@comparison:comparison(GBB))
+) -> gap@comparison:comparison(GBB).
+compare_lists_with_algorithm(First_sequence, Second_sequence, Algorithm) ->
+ Algorithm(First_sequence, Second_sequence).
+
+-spec myers(list(GBG), list(GBG)) -> gap@comparison:comparison(GBG).
+myers(First_sequence, Second_sequence) ->
+ Edits = gap@myers:difference(First_sequence, Second_sequence),
+ _pipe = Edits,
+ _pipe@1 = gleam@list:reverse(_pipe),
+ gleam@list:fold(
+ _pipe@1,
+ {list_comparison, [], []},
+ fun(Comparison, Edit) -> case Comparison of
+ {list_comparison, First, Second} ->
+ case Edit of
+ {eq, Segment} ->
+ {list_comparison,
+ [{match, Segment} | First],
+ [{match, Segment} | Second]};
+
+ {ins, Segment@1} ->
+ {list_comparison,
+ First,
+ [{no_match, Segment@1} | Second]};
+
+ {del, Segment@2} ->
+ {list_comparison,
+ [{no_match, Segment@2} | First],
+ Second}
+ end;
+
+ {string_comparison, _, _} ->
+ Comparison
+ end end
+ ).
+
+-spec compare_lists(list(GAX), list(GAX)) -> gap@comparison:comparison(GAX).
+compare_lists(First_sequence, Second_sequence) ->
+ myers(First_sequence, Second_sequence).
+
+-spec compare_strings(binary(), binary()) -> gap@comparison:comparison(binary()).
+compare_strings(First, Second) ->
+ Comparison = compare_lists(
+ gleam@string:to_graphemes(First),
+ gleam@string:to_graphemes(Second)
+ ),
+ case Comparison of
+ {list_comparison, First@1, Second@1} ->
+ {string_comparison, First@1, Second@1};
+
+ {string_comparison, First@2, Second@2} ->
+ {string_comparison, First@2, Second@2}
+ end.
+
+-spec prepend_and_merge(
+ list(gap@comparison:match(list(GBO))),
+ gap@comparison:match(list(GBO))
+) -> list(gap@comparison:match(list(GBO))).
+prepend_and_merge(Matches, Match) ->
+ case {Matches, Match} of
+ {[], _} ->
+ [Match];
+
+ {[{match, First_match} | Rest], {match, _}} ->
+ [{match,
+ begin
+ _pipe = erlang:element(2, Match),
+ gleam@list:append(_pipe, First_match)
+ end} |
+ Rest];
+
+ {[{no_match, First_match@1} | Rest@1], {no_match, _}} ->
+ [{no_match,
+ begin
+ _pipe@1 = erlang:element(2, Match),
+ gleam@list:append(_pipe@1, First_match@1)
+ end} |
+ Rest@1];
+
+ {Matches@1, Match@1} ->
+ [Match@1 | Matches@1]
+ end.
+
+-spec append_and_merge(
+ list(gap@comparison:match(list(GBX))),
+ gap@comparison:match(list(GBX))
+) -> list(gap@comparison:match(list(GBX))).
+append_and_merge(Matches, Match) ->
+ _pipe@3 = case {begin
+ _pipe = Matches,
+ gleam@list:reverse(_pipe)
+ end,
+ Match} of
+ {[], _} ->
+ [Match];
+
+ {[{match, First_match} | Rest], {match, _}} ->
+ [{match,
+ begin
+ _pipe@1 = First_match,
+ gleam@list:append(_pipe@1, erlang:element(2, Match))
+ end} |
+ Rest];
+
+ {[{no_match, First_match@1} | Rest@1], {no_match, _}} ->
+ [{no_match,
+ begin
+ _pipe@2 = First_match@1,
+ gleam@list:append(_pipe@2, erlang:element(2, Match))
+ end} |
+ Rest@1];
+
+ {Matches@1, Match@1} ->
+ [Match@1 | Matches@1]
+ end,
+ gleam@list:reverse(_pipe@3).
+
+-spec collect_matches(
+ gleam@map:map_(GFY, any()),
+ list(GCH),
+ fun((GFY) -> integer())
+) -> list(gap@comparison:match(list(GCH))).
+collect_matches(Tracking, Str, Extract_fun) ->
+ Matching_indexes = begin
+ _pipe = gleam@map:keys(Tracking),
+ _pipe@1 = gleam@list:map(_pipe, Extract_fun),
+ gleam@set:from_list(_pipe@1)
+ end,
+ Matches = begin
+ _pipe@2 = Str,
+ gleam@list:index_map(
+ _pipe@2,
+ fun(Index, Item) ->
+ case gleam@set:contains(Matching_indexes, Index) of
+ true ->
+ {match, Item};
+
+ false ->
+ {no_match, Item}
+ end
+ end
+ )
+ end,
+ _pipe@3 = Matches,
+ _pipe@4 = gleam@list:chunk(_pipe@3, fun(Match) -> case Match of
+ {match, _} ->
+ true;
+
+ {no_match, _} ->
+ false
+ end end),
+ gleam@list:map(_pipe@4, fun(Match_list) -> case Match_list of
+ [{match, _} | _] ->
+ {match,
+ gleam@list:filter_map(
+ Match_list,
+ fun(Match@1) -> case Match@1 of
+ {match, Item@1} ->
+ {ok, Item@1};
+
+ {no_match, _} ->
+ {error, nil}
+ end end
+ )};
+
+ [{no_match, _} | _] ->
+ {no_match,
+ gleam@list:filter_map(
+ Match_list,
+ fun(Match@2) -> case Match@2 of
+ {no_match, Item@2} ->
+ {ok, Item@2};
+
+ {match, _} ->
+ {error, nil}
+ end end
+ )}
+ end end).
+
+-spec back_track(
+ gleam@map:map_({integer(), integer()}, score(GCL)),
+ integer(),
+ integer(),
+ list({{integer(), integer()}, GCL})
+) -> list({{integer(), integer()}, GCL}).
+back_track(Diff_map, First_index, Second_index, Stack) ->
+ case (First_index =:= 0) orelse (Second_index =:= 0) of
+ true ->
+ This_score = begin
+ _pipe = gleam@map:get(Diff_map, {First_index, Second_index}),
+ gleam@result:unwrap(_pipe, {score, 0, none})
+ end,
+ case This_score of
+ {score, _, {some, Item}} ->
+ [{{First_index, Second_index}, Item} | Stack];
+
+ _ ->
+ case {First_index, Second_index} of
+ {0, A} when A > 0 ->
+ back_track(
+ Diff_map,
+ First_index,
+ Second_index - 1,
+ Stack
+ );
+
+ {A@1, 0} when A@1 > 0 ->
+ back_track(
+ Diff_map,
+ First_index - 1,
+ Second_index,
+ Stack
+ );
+
+ {0, 0} ->
+ Stack;
+
+ {_, _} ->
+ back_track(
+ Diff_map,
+ First_index - 1,
+ Second_index,
+ Stack
+ )
+ end
+ end;
+
+ false ->
+ This_score@1 = begin
+ _pipe@1 = gleam@map:get(Diff_map, {First_index, Second_index}),
+ gleam@result:unwrap(_pipe@1, {score, 0, none})
+ end,
+ case This_score@1 of
+ {score, _, {some, Item@1}} ->
+ back_track(
+ Diff_map,
+ First_index - 1,
+ Second_index - 1,
+ [{{First_index, Second_index}, Item@1} | Stack]
+ );
+
+ {score, _, none} ->
+ Up = begin
+ _pipe@2 = gleam@map:get(
+ Diff_map,
+ {First_index, Second_index - 1}
+ ),
+ gleam@result:unwrap(_pipe@2, {score, 0, none})
+ end,
+ Back = begin
+ _pipe@3 = gleam@map:get(
+ Diff_map,
+ {First_index - 1, Second_index}
+ ),
+ gleam@result:unwrap(_pipe@3, {score, 0, none})
+ end,
+ case gleam@int:compare(
+ erlang:element(2, Up),
+ erlang:element(2, Back)
+ ) of
+ gt ->
+ back_track(
+ Diff_map,
+ First_index,
+ Second_index - 1,
+ Stack
+ );
+
+ lt ->
+ back_track(
+ Diff_map,
+ First_index - 1,
+ Second_index,
+ Stack
+ );
+
+ eq ->
+ case {First_index, Second_index} of
+ {0, A@2} when A@2 > 0 ->
+ back_track(
+ Diff_map,
+ First_index,
+ Second_index - 1,
+ Stack
+ );
+
+ {A@3, 0} when A@3 > 0 ->
+ back_track(
+ Diff_map,
+ First_index - 1,
+ Second_index,
+ Stack
+ );
+
+ {0, 0} ->
+ Stack;
+
+ {_, _} ->
+ back_track(
+ Diff_map,
+ First_index - 1,
+ Second_index,
+ Stack
+ )
+ end
+ end
+ end
+ end.
+
+-spec build_diff_map(
+ GCR,
+ integer(),
+ GCR,
+ integer(),
+ gleam@map:map_({integer(), integer()}, score(GCR))
+) -> gleam@map:map_({integer(), integer()}, score(GCR)).
+build_diff_map(First_item, First_index, Second_item, Second_index, Diff_map) ->
+ Prev_score = begin
+ _pipe = gleam@map:get(Diff_map, {First_index - 1, Second_index - 1}),
+ gleam@result:unwrap(_pipe, {score, 0, none})
+ end,
+ Derived_score_up = begin
+ _pipe@1 = Diff_map,
+ _pipe@2 = gleam@map:get(_pipe@1, {First_index, Second_index - 1}),
+ gleam@result:unwrap(_pipe@2, {score, 0, none})
+ end,
+ Derived_score_back = begin
+ _pipe@3 = Diff_map,
+ _pipe@4 = gleam@map:get(_pipe@3, {First_index - 1, Second_index}),
+ gleam@result:unwrap(_pipe@4, {score, 0, none})
+ end,
+ Derived_score = gleam@int:max(
+ erlang:element(2, Derived_score_up),
+ erlang:element(2, Derived_score_back)
+ ),
+ This_score = case First_item =:= Second_item of
+ true ->
+ {score, erlang:element(2, Prev_score) + 1, {some, First_item}};
+
+ false ->
+ {score, Derived_score, none}
+ end,
+ _pipe@5 = Diff_map,
+ gleam@map:insert(_pipe@5, {First_index, Second_index}, This_score).
+
+-spec lcs(list(GBK), list(GBK)) -> gap@comparison:comparison(GBK).
+lcs(First_sequence, Second_sequence) ->
+ Leading_matches = begin
+ _pipe = gleam@list:zip(First_sequence, Second_sequence),
+ _pipe@1 = gleam@list:take_while(
+ _pipe,
+ fun(Pair) -> erlang:element(1, Pair) =:= erlang:element(2, Pair) end
+ ),
+ gleam@list:map(_pipe@1, fun gleam@pair:first/1)
+ end,
+ Num_leading_matches = gleam@list:length(Leading_matches),
+ Trailing_matches = begin
+ _pipe@2 = gleam@list:zip(
+ gleam@list:reverse(First_sequence),
+ gleam@list:reverse(Second_sequence)
+ ),
+ _pipe@3 = gleam@list:take_while(
+ _pipe@2,
+ fun(Pair@1) ->
+ erlang:element(1, Pair@1) =:= erlang:element(2, Pair@1)
+ end
+ ),
+ _pipe@4 = gleam@list:map(_pipe@3, fun gleam@pair:first/1),
+ gleam@list:reverse(_pipe@4)
+ end,
+ Num_trailing_matches = gleam@list:length(Trailing_matches),
+ First_sequence_to_diff = begin
+ _pipe@5 = First_sequence,
+ _pipe@6 = gleam@list:drop(_pipe@5, Num_leading_matches),
+ gleam@list:take(
+ _pipe@6,
+ (gleam@list:length(First_sequence) - Num_leading_matches) - Num_trailing_matches
+ )
+ end,
+ Second_sequence_to_diff = begin
+ _pipe@7 = Second_sequence,
+ _pipe@8 = gleam@list:drop(_pipe@7, Num_leading_matches),
+ gleam@list:take(
+ _pipe@8,
+ (gleam@list:length(Second_sequence) - Num_leading_matches) - Num_trailing_matches
+ )
+ end,
+ Diff_map@2 = begin
+ _pipe@9 = Second_sequence_to_diff,
+ gleam@list:index_fold(
+ _pipe@9,
+ gleam@map:new(),
+ fun(Diff_map, Item_second, Index_second) ->
+ _pipe@10 = First_sequence_to_diff,
+ gleam@list:index_fold(
+ _pipe@10,
+ Diff_map,
+ fun(Diff_map@1, Item_first, Index_first) ->
+ build_diff_map(
+ Item_first,
+ Index_first,
+ Item_second,
+ Index_second,
+ Diff_map@1
+ )
+ end
+ )
+ end
+ )
+ end,
+ {First_segments@1, Second_segments@1} = case {First_sequence_to_diff,
+ Second_sequence_to_diff} of
+ {[], []} ->
+ {[], []};
+
+ {First_matching, []} ->
+ {[{no_match, First_matching}], []};
+
+ {[], Second_matching} ->
+ {[], [{no_match, Second_matching}]};
+
+ {First_sequence_to_diff@1, Second_sequence_to_diff@1} ->
+ Tracking = begin
+ _pipe@11 = back_track(
+ Diff_map@2,
+ gleam@list:length(First_sequence_to_diff@1) - 1,
+ gleam@list:length(Second_sequence_to_diff@1) - 1,
+ []
+ ),
+ gleam@map:from_list(_pipe@11)
+ end,
+ First_segments = collect_matches(
+ Tracking,
+ First_sequence_to_diff@1,
+ fun(Key) ->
+ {First, _} = Key,
+ First
+ end
+ ),
+ Second_segments = collect_matches(
+ Tracking,
+ Second_sequence_to_diff@1,
+ fun(Key@1) ->
+ {_, Second} = Key@1,
+ Second
+ end
+ ),
+ {First_segments, Second_segments}
+ end,
+ {First_segments_with_leading_trailing,
+ Second_segments_with_leading_trailing} = case {Leading_matches,
+ Trailing_matches} of
+ {[], []} ->
+ {First_segments@1, Second_segments@1};
+
+ {[], Trailing_matches@1} ->
+ {begin
+ _pipe@12 = First_segments@1,
+ append_and_merge(_pipe@12, {match, Trailing_matches@1})
+ end,
+ begin
+ _pipe@13 = Second_segments@1,
+ append_and_merge(_pipe@13, {match, Trailing_matches@1})
+ end};
+
+ {Leading_matches@1, []} ->
+ {begin
+ _pipe@14 = First_segments@1,
+ prepend_and_merge(_pipe@14, {match, Leading_matches@1})
+ end,
+ begin
+ _pipe@15 = Second_segments@1,
+ prepend_and_merge(_pipe@15, {match, Leading_matches@1})
+ end};
+
+ {Leading_matches@2, Trailing_matches@2} ->
+ {begin
+ _pipe@16 = First_segments@1,
+ _pipe@17 = prepend_and_merge(
+ _pipe@16,
+ {match, Leading_matches@2}
+ ),
+ append_and_merge(_pipe@17, {match, Trailing_matches@2})
+ end,
+ begin
+ _pipe@18 = Second_segments@1,
+ _pipe@19 = prepend_and_merge(
+ _pipe@18,
+ {match, Leading_matches@2}
+ ),
+ append_and_merge(_pipe@19, {match, Trailing_matches@2})
+ end}
+ end,
+ {list_comparison,
+ First_segments_with_leading_trailing,
+ Second_segments_with_leading_trailing}.