-module(qrkit@internal@mask).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/qrkit/internal/mask.gleam").
-export([penalty_n4/1, mask_at/3, apply/2, penalty_n1/1, penalty_n2/1, penalty_n3/1, penalty_total/1, best_mask/1]).
-if(?OTP_RELEASE >= 27).
-define(MODULEDOC(Str), -moduledoc(Str)).
-define(DOC(Str), -doc(Str)).
-else.
-define(MODULEDOC(Str), -compile([])).
-define(DOC(Str), -compile([])).
-endif.
?MODULEDOC(false).
-file("src/qrkit/internal/mask.gleam", 112).
?DOC(false).
-spec run_penalty(integer()) -> integer().
run_penalty(Run_length) ->
case Run_length >= 5 of
true ->
(3 + Run_length) - 5;
false ->
0
end.
-file("src/qrkit/internal/mask.gleam", 95).
?DOC(false).
-spec line_penalty_loop(list(boolean()), boolean(), integer(), integer()) -> integer().
line_penalty_loop(Values, Last, Run_length, Penalty) ->
case Values of
[] ->
Penalty + run_penalty(Run_length);
[Value | Rest] ->
case Value =:= Last of
true ->
line_penalty_loop(Rest, Last, Run_length + 1, Penalty);
false ->
line_penalty_loop(
Rest,
Value,
1,
Penalty + run_penalty(Run_length)
)
end
end.
-file("src/qrkit/internal/mask.gleam", 88).
?DOC(false).
-spec line_penalty(list(boolean())) -> integer().
line_penalty(Values) ->
case Values of
[] ->
0;
[First | Rest] ->
line_penalty_loop(Rest, First, 1, 0)
end.
-file("src/qrkit/internal/mask.gleam", 187).
?DOC(false).
-spec penalty_n4(qrkit@internal@matrix:matrix()) -> integer().
penalty_n4(Target) ->
Dark = qrkit@internal@matrix:dark_count(Target),
Total = qrkit@internal@matrix:total_cells(Target),
Percentage = case Total of
0 -> 0;
Gleam@denominator -> Dark * 100 div Gleam@denominator
end,
Deviation = Percentage - 50,
Absolute = case Deviation < 0 of
true ->
0 - Deviation;
false ->
Deviation
end,
Lower_bucket = Absolute div 5,
Lower_bucket * 10.
-file("src/qrkit/internal/mask.gleam", 200).
?DOC(false).
-spec mask_at(integer(), integer(), integer()) -> boolean().
mask_at(Mask, Row, Col) ->
case Mask of
0 ->
((Row + Col) rem 2) =:= 0;
1 ->
(Row rem 2) =:= 0;
2 ->
(Col rem 3) =:= 0;
3 ->
((Row + Col) rem 3) =:= 0;
4 ->
(((Row div 2) + (Col div 3)) rem 2) =:= 0;
5 ->
(((Row * Col) rem 2) + ((Row * Col) rem 3)) =:= 0;
6 ->
((((Row * Col) rem 2) + ((Row * Col) rem 3)) rem 2) =:= 0;
_ ->
((((Row * Col) rem 3) + ((Row + Col) rem 2)) rem 2) =:= 0
end.
-file("src/qrkit/internal/mask.gleam", 11).
?DOC(false).
-spec do_apply(integer(), qrkit@internal@matrix:matrix(), integer(), integer()) -> qrkit@internal@matrix:matrix().
do_apply(Mask, Target, Row, Col) ->
case Row >= qrkit@internal@matrix:height(Target) of
true ->
Target;
false ->
case Col >= qrkit@internal@matrix:width(Target) of
true ->
do_apply(Mask, Target, Row + 1, 0);
false ->
case qrkit@internal@matrix:is_reserved(Target, Row, Col) of
true ->
do_apply(Mask, Target, Row, Col + 1);
false ->
do_apply(
Mask,
qrkit@internal@matrix:'xor'(
Target,
Row,
Col,
mask_at(Mask, Row, Col)
),
Row,
Col + 1
)
end
end
end.
-file("src/qrkit/internal/mask.gleam", 7).
?DOC(false).
-spec apply(integer(), qrkit@internal@matrix:matrix()) -> qrkit@internal@matrix:matrix().
apply(Mask, Target) ->
do_apply(Mask, Target, 0, 0).
-file("src/qrkit/internal/mask.gleam", 213).
?DOC(false).
-spec row_values(qrkit@internal@matrix:matrix(), integer()) -> list(boolean()).
row_values(Target, Row) ->
_pipe = qrkit@internal@util:range(
0,
qrkit@internal@matrix:width(Target) - 1
),
gleam@list:map(
_pipe,
fun(Col) -> qrkit@internal@matrix:get(Target, Row, Col) end
).
-file("src/qrkit/internal/mask.gleam", 218).
?DOC(false).
-spec column_values(qrkit@internal@matrix:matrix(), integer()) -> list(boolean()).
column_values(Target, Col) ->
_pipe = qrkit@internal@util:range(
0,
qrkit@internal@matrix:height(Target) - 1
),
gleam@list:map(
_pipe,
fun(Row) -> qrkit@internal@matrix:get(Target, Row, Col) end
).
-file("src/qrkit/internal/mask.gleam", 70).
?DOC(false).
-spec penalty_runs(
qrkit@internal@matrix:matrix(),
integer(),
integer(),
integer()
) -> integer().
penalty_runs(Target, Row, Col_points, Row_points) ->
case Row >= qrkit@internal@matrix:height(Target) of
true ->
Col_points + Row_points;
false ->
penalty_runs(
Target,
Row + 1,
Col_points + line_penalty(column_values(Target, Row)),
Row_points + line_penalty(row_values(Target, Row))
)
end.
-file("src/qrkit/internal/mask.gleam", 66).
?DOC(false).
-spec penalty_n1(qrkit@internal@matrix:matrix()) -> integer().
penalty_n1(Target) ->
penalty_runs(Target, 0, 0, 0).
-file("src/qrkit/internal/mask.gleam", 223).
?DOC(false).
-spec bool_to_int(boolean()) -> integer().
bool_to_int(Value) ->
case Value of
true ->
1;
false ->
0
end.
-file("src/qrkit/internal/mask.gleam", 123).
?DOC(false).
-spec do_penalty_n2(
qrkit@internal@matrix:matrix(),
integer(),
integer(),
integer()
) -> integer().
do_penalty_n2(Target, Row, Col, Acc) ->
case Row >= (qrkit@internal@matrix:height(Target) - 1) of
true ->
Acc * 3;
false ->
case Col >= (qrkit@internal@matrix:width(Target) - 1) of
true ->
do_penalty_n2(Target, Row + 1, 0, Acc);
false ->
Dark_total = ((bool_to_int(
qrkit@internal@matrix:get(Target, Row, Col)
)
+ bool_to_int(
qrkit@internal@matrix:get(Target, Row, Col + 1)
))
+ bool_to_int(
qrkit@internal@matrix:get(Target, Row + 1, Col)
))
+ bool_to_int(
qrkit@internal@matrix:get(Target, Row + 1, Col + 1)
),
Next_acc = case (Dark_total =:= 0) orelse (Dark_total =:= 4) of
true ->
Acc + 1;
false ->
Acc
end,
do_penalty_n2(Target, Row, Col + 1, Next_acc)
end
end.
-file("src/qrkit/internal/mask.gleam", 119).
?DOC(false).
-spec penalty_n2(qrkit@internal@matrix:matrix()) -> integer().
penalty_n2(Target) ->
do_penalty_n2(Target, 0, 0, 0).
-file("src/qrkit/internal/mask.gleam", 178).
?DOC(false).
-spec take_bits(list(boolean()), integer(), integer()) -> integer().
take_bits(Values, Count, Acc) ->
case {Values, Count} of
{_, 0} ->
Acc;
{[Value | Rest], _} ->
take_bits(Rest, Count - 1, (Acc * 2) + bool_to_int(Value));
{[], _} ->
Acc
end.
-file("src/qrkit/internal/mask.gleam", 159).
?DOC(false).
-spec finder_like_penalty(list(boolean())) -> integer().
finder_like_penalty(Values) ->
case Values of
[] ->
0;
_ ->
case erlang:length(Values) < 11 of
true ->
0;
false ->
Bits = take_bits(Values, 11, 0),
Rest = gleam@list:drop(Values, 1),
Points = case (Bits =:= 16#5D0) orelse (Bits =:= 16#05D) of
true ->
1;
false ->
0
end,
Points + finder_like_penalty(Rest)
end
end.
-file("src/qrkit/internal/mask.gleam", 145).
?DOC(false).
-spec penalty_n3(qrkit@internal@matrix:matrix()) -> integer().
penalty_n3(Target) ->
Rows = begin
_pipe = qrkit@internal@util:range(
0,
qrkit@internal@matrix:height(Target) - 1
),
gleam@list:fold(
_pipe,
0,
fun(Acc, Row) ->
Acc + finder_like_penalty(row_values(Target, Row))
end
)
end,
Columns = begin
_pipe@1 = qrkit@internal@util:range(
0,
qrkit@internal@matrix:width(Target) - 1
),
gleam@list:fold(
_pipe@1,
0,
fun(Acc@1, Col) ->
Acc@1 + finder_like_penalty(column_values(Target, Col))
end
)
end,
(Rows + Columns) * 40.
-file("src/qrkit/internal/mask.gleam", 59).
?DOC(false).
-spec penalty_total(qrkit@internal@matrix:matrix()) -> integer().
penalty_total(Target) ->
((penalty_n1(Target) + penalty_n2(Target)) + penalty_n3(Target)) + penalty_n4(
Target
).
-file("src/qrkit/internal/mask.gleam", 41).
?DOC(false).
-spec do_best_mask(
qrkit@internal@matrix:matrix(),
integer(),
integer(),
integer()
) -> integer().
do_best_mask(Target, Mask, Best_mask, Best_penalty) ->
case Mask > 7 of
true ->
Best_mask;
false ->
Penalty = penalty_total(apply(Mask, Target)),
case (Mask =:= 0) orelse (Penalty < Best_penalty) of
true ->
do_best_mask(Target, Mask + 1, Mask, Penalty);
false ->
do_best_mask(Target, Mask + 1, Best_mask, Best_penalty)
end
end.
-file("src/qrkit/internal/mask.gleam", 37).
?DOC(false).
-spec best_mask(qrkit@internal@matrix:matrix()) -> integer().
best_mask(Target) ->
do_best_mask(Target, 0, 0, 0).