Current section
Files
Jump to
Current section
Files
src/bibi@bitboard.erl
-module(bibi@bitboard).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]).
-export([new/2, from_base2/3, from_coords/3, from_list_of_coords/3, from_square/3, to_string/1, to_squares/1, to_bools/1, full_mask/1, rank/2, file/2, bitboard_and/2, bitboard_or/2, bitboard_not/1, shift_north/2, shift_south/2, shift_west/2, shift_east/2, diagonal/2, antidiagonal/2, flip_vertically/1, flip_horizontally/1]).
-export_type([bitboard/0]).
-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(
" The bibi/bitboard module provides the ability to create and manipulate bitboards.\n"
" Bitboards have a defined width and height, and an integer that represents the\n"
" state of the bitboard when in binary\n"
"\n"
" Suppose you are representing a game of tic-tac-toe that looks like\n"
"\n"
"```\n"
" X | O | _\n"
" - + - + -\n"
" O | X | _\n"
" - + - + -\n"
" O | _ | X\n"
" ```\n"
" Representing the X's as a bitboard, it would look like\n"
" ```\n"
" 100\n"
" 010\n"
" 001\n"
" ```\n"
"\n"
" In binary, this would be `001010100`, which translates to 84\n"
"\n"
" Notice that the positions of the 1's when the bitboard is translated into its\n"
" binary integer format\n"
"\n"
" The following diagram shows how the individual bits are ordered from right to left\n"
" ```\n"
" 6 7 8\n"
" 3 4 5\n"
" 0 1 2\n"
" ```\n"
"\n"
" To disambiguate between the bitwise shift operations in the `int` modules and bitboard shifts\n"
" we use cardinal directions when describing and manipulating bitboards.\n"
"\n"
" ```\n"
" north\n"
"\n"
" 000\n"
" west 000 east\n"
" 000\n"
"\n"
" south\n"
" ```\n"
"\n"
).
-type bitboard() :: {bitboard, integer(), integer(), integer()}.
-file("src/bibi/bitboard.gleam", 63).
?DOC(
" Internal validator for ensuring bitboards are of the same dimension before bitboard\n"
" operations are performed\n"
).
-spec validate_equal_dimensions(bitboard(), bitboard()) -> {ok, nil} |
{error, binary()}.
validate_equal_dimensions(Bitboard_1, Bitboard_2) ->
gleam@bool:guard(
erlang:element(2, Bitboard_1) /= erlang:element(2, Bitboard_2),
{error, <<"bitboard widths must be equal"/utf8>>},
fun() ->
gleam@bool:guard(
erlang:element(3, Bitboard_1) /= erlang:element(3, Bitboard_2),
{error, <<"bitboard heights must be equal"/utf8>>},
fun() -> {ok, nil} end
)
end
).
-file("src/bibi/bitboard.gleam", 80).
?DOC(
" Internal validator for ensuring that coordinates are on the bitboard before\n"
" bitboard operations are performed\n"
).
-spec validate_coords(bibi@coords:coords(), integer(), integer()) -> {ok, nil} |
{error, binary()}.
validate_coords(Coords, Width, Height) ->
gleam@bool:guard(
erlang:element(2, Coords) < 0,
{error, <<"Coords.x must be positive"/utf8>>},
fun() ->
gleam@bool:guard(
erlang:element(3, Coords) < 0,
{error, <<"Coords.y must be positive"/utf8>>},
fun() ->
gleam@bool:guard(
erlang:element(2, Coords) >= Width,
{error, <<"Coords.x must be less than width"/utf8>>},
fun() ->
gleam@bool:guard(
erlang:element(3, Coords) >= Height,
{error,
<<"Coords.y must be less than height"/utf8>>},
fun() -> {ok, nil} end
)
end
)
end
)
end
).
-file("src/bibi/bitboard.gleam", 101).
?DOC(
" Internal validator for ensuring that coordinates are on the bitboard before\n"
" bitboard operations are performed\n"
).
-spec validate_coords_list(list(bibi@coords:coords()), integer(), integer()) -> {ok,
nil} |
{error, binary()}.
validate_coords_list(Coords_list, Width, Height) ->
case Coords_list of
[First | Remaining] ->
Result = validate_coords(First, Width, Height),
case Result of
{ok, _} ->
validate_coords_list(Remaining, Width, Height);
_ ->
Result
end;
_ ->
{ok, nil}
end.
-file("src/bibi/bitboard.gleam", 119).
?DOC(" Create an empty bitboard of a given width and height\n").
-spec new(integer(), integer()) -> {ok, bitboard()} | {error, binary()}.
new(Width, Height) ->
gleam@bool:guard(
Width < 0,
{error, <<"width must be positive"/utf8>>},
fun() ->
gleam@bool:guard(
Height < 0,
{error, <<"height must be positive"/utf8>>},
fun() -> {ok, {bitboard, Width, Height, 0}} end
)
end
).
-file("src/bibi/bitboard.gleam", 129).
?DOC(
" Create a bitboard of a given width and height, and a binary string\n"
"\n"
" i.e.\n"
" `from_base2(3, 3, \"000000111\")` --> `Bitboard(width: 3, height: 3, val: 7)`\n"
).
-spec from_base2(integer(), integer(), binary()) -> {ok, bitboard()} |
{error, binary()}.
from_base2(Width, Height, Bits) ->
gleam@bool:guard(
Width < 0,
{error, <<"width must be positive"/utf8>>},
fun() ->
gleam@bool:guard(
Height < 0,
{error, <<"height must be positive"/utf8>>},
fun() ->
_assert_subject = gleam@int:base_parse(Bits, 2),
{ok, Val} = case _assert_subject of
{ok, _} -> _assert_subject;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
value => _assert_fail,
module => <<"bibi/bitboard"/utf8>>,
function => <<"from_base2"/utf8>>,
line => 133})
end,
gleam@bool:guard(
Val >= erlang:'bsl'(1, Width * Height),
{error,
<<"bits must be less than 1 << width * height"/utf8>>},
fun() -> {ok, {bitboard, Width, Height, Val}} end
)
end
)
end
).
-file("src/bibi/bitboard.gleam", 145).
?DOC(
" Create a bitboard of a given width and height, and a Coords\n"
"\n"
" i.e.\n"
" `from_coords(3, 3, Coords(0, 0))` --> `Bitboard(width: 3, height: 3, val: 1)`\n"
).
-spec from_coords(integer(), integer(), bibi@coords:coords()) -> {ok,
bitboard()} |
{error, binary()}.
from_coords(Width, Height, Coords) ->
gleam@bool:guard(
Width < 0,
{error, <<"width must be positive"/utf8>>},
fun() ->
gleam@bool:guard(
Height < 0,
{error, <<"height must be positive"/utf8>>},
fun() ->
Result = validate_coords(Coords, Width, Height),
case Result of
{ok, _} ->
Val = erlang:'bsl'(
1,
(Width * erlang:element(3, Coords)) + erlang:element(
2,
Coords
)
),
{ok, {bitboard, Width, Height, Val}};
{error, Message} ->
{error, Message}
end
end
)
end
).
-file("src/bibi/bitboard.gleam", 162).
?DOC(
" Create a bitboard of a given width and height, and a list of Coords\n"
"\n"
" i.e.\n"
" `from_coords(3, 3, [Coords(0, 0), Coords(1, 0)])` --> `Bitboard(width: 3, height: 3, val: 3)`\n"
).
-spec from_list_of_coords(integer(), integer(), list(bibi@coords:coords())) -> {ok,
bitboard()} |
{error, binary()}.
from_list_of_coords(Width, Height, Coords_list) ->
gleam@bool:guard(
Width < 0,
{error, <<"width must be positive"/utf8>>},
fun() ->
gleam@bool:guard(
Height < 0,
{error, <<"height must be positive"/utf8>>},
fun() ->
Result = validate_coords_list(Coords_list, Width, Height),
case Result of
{ok, _} ->
Val = begin
_pipe = Coords_list,
gleam@list:fold(
_pipe,
0,
fun(Acc, Coords) ->
erlang:'bor'(
Acc,
erlang:'bsl'(
1,
(Width * erlang:element(
3,
Coords
))
+ erlang:element(2, Coords)
)
)
end
)
end,
{ok, {bitboard, Width, Height, Val}};
{error, Message} ->
{error, Message}
end
end
)
end
).
-file("src/bibi/bitboard.gleam", 196).
?DOC(
" Create a bitboard of a given with and height, and the nth square\n"
"\n"
" i.e. `from_square(3, 3, 1)` --> `Bitboard(width: 3, height: 3, val: 2)`\n"
"\n"
" Squares are indexed from bottom left to top right. A 3 by 3 bitboard will be indexed as follows\n"
" ```\n"
" 6 7 8\n"
" 3 4 5\n"
" 0 1 2\n"
" ```\n"
).
-spec from_square(integer(), integer(), integer()) -> {ok, bitboard()} |
{error, binary()}.
from_square(Width, Height, Square) ->
gleam@bool:guard(
Width < 0,
{error, <<"width must be positive"/utf8>>},
fun() ->
gleam@bool:guard(
Height < 0,
{error, <<"height must be positive"/utf8>>},
fun() ->
gleam@bool:guard(
Square > (Width * Height),
{error,
<<<<<<<<<<<<<<"square ("/utf8,
(erlang:integer_to_binary(
Square
))/binary>>/binary,
") must be less than width ("/utf8>>/binary,
(erlang:integer_to_binary(Width))/binary>>/binary,
") *"/utf8>>/binary,
"height ("/utf8>>/binary,
(erlang:integer_to_binary(Height))/binary>>/binary,
")"/utf8>>},
fun() ->
{ok,
{bitboard,
Width,
Height,
erlang:'bsl'(1, Square)}}
end
)
end
)
end
).
-file("src/bibi/bitboard.gleam", 223).
?DOC(
" Converts a bitboard into a width * height, breakpoint separated string of 1s and 0s\n"
"\n"
" i.e. `to_string(Bitboard(width: 3, height: 3, val: 2))` -->\n"
" ```\n"
" 000\n"
" 000\n"
" 010\n"
" ````\n"
).
-spec to_string(bitboard()) -> binary().
to_string(Bitboard) ->
_pipe = erlang:element(4, Bitboard),
_pipe@1 = gleam@int:to_base2(_pipe),
_pipe@2 = gleam@string:pad_start(
_pipe@1,
erlang:element(2, Bitboard) * erlang:element(3, Bitboard),
<<"0"/utf8>>
),
_pipe@3 = gleam@string:split(_pipe@2, <<""/utf8>>),
_pipe@4 = gleam@list:fold(
_pipe@3,
[<<""/utf8>>],
fun(Acc, Str) ->
[First | Rest] = case Acc of
[_ | _] -> Acc;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
value => _assert_fail,
module => <<"bibi/bitboard"/utf8>>,
function => <<"to_string"/utf8>>,
line => 229})
end,
case string:length(First) >= erlang:element(2, Bitboard) of
true ->
[Str, First | Rest];
false ->
[<<Str/binary, First/binary>> | Rest]
end
end
),
_pipe@5 = lists:reverse(_pipe@4),
gleam@string:join(_pipe@5, <<"\n"/utf8>>).
-file("src/bibi/bitboard.gleam", 242).
?DOC(
" Converts a bitboard into a list of integers representing where a square is occupied\n"
"\n"
" i.e `to_squares(Bitboard(width: 3, height: 3, val: 3))` --> `[0, 1]`\n"
).
-spec to_squares(bitboard()) -> list(integer()).
to_squares(B) ->
Result = begin
_pipe = gleam@list:range(
0,
(erlang:element(2, B) * erlang:element(3, B)) - 1
),
gleam@list:fold_until(
_pipe,
{erlang:element(4, B), []},
fun(Acc, I) ->
{Board, L} = Acc,
L@1 = case erlang:'band'(1, Board) > 0 of
true ->
[I | L];
false ->
L
end,
Board@1 = erlang:'bsr'(Board, 1),
case Board@1 > 0 of
true ->
{continue, {Board@1, L@1}};
false ->
{stop, {Board@1, L@1}}
end
end
)
end,
erlang:element(2, Result).
-file("src/bibi/bitboard.gleam", 265).
?DOC(
" Convers a bitboard into a list of booleans representing where a square is occupied\n"
"\n"
" i.e\n"
" `to_bools(Bitboard(width: 3, height: 3, val: 3))` --> `[True, True, False,... ]` (False repeats 7 times in this example)\n"
).
-spec to_bools(bitboard()) -> list(boolean()).
to_bools(B) ->
_pipe = gleam@list:range(
0,
(erlang:element(2, B) * erlang:element(3, B)) - 1
),
gleam@list:fold(
_pipe,
[],
fun(Acc, I) ->
Has_bit = erlang:'band'(erlang:'bsl'(1, I), erlang:element(4, B)) > 0,
lists:append(Acc, [Has_bit])
end
).
-file("src/bibi/bitboard.gleam", 273).
-spec int_full_mask(bitboard()) -> integer().
int_full_mask(B) ->
erlang:'bsl'(1, erlang:element(2, B) * erlang:element(3, B)) - 1.
-file("src/bibi/bitboard.gleam", 285).
?DOC(
" This returns a bitboard that is fully occupied\n"
"\n"
" i.e.\n"
" ```\n"
" 111\n"
" full_mask(Bitboard(3, 3, 1)) --> 111\n"
" 111\n"
" ```\n"
).
-spec full_mask(bitboard()) -> bitboard().
full_mask(B) ->
_record = B,
{bitboard,
erlang:element(2, _record),
erlang:element(3, _record),
int_full_mask(B)}.
-file("src/bibi/bitboard.gleam", 290).
-spec first_rank(bitboard(), integer(), integer()) -> bitboard().
first_rank(Bitboard, Counter, Val) ->
case Counter >= erlang:element(2, Bitboard) of
true ->
_record = Bitboard,
{bitboard,
erlang:element(2, _record),
erlang:element(3, _record),
Val};
false ->
first_rank(
Bitboard,
Counter + 1,
erlang:'bor'(erlang:'bsl'(1, Counter), Val)
)
end.
-file("src/bibi/bitboard.gleam", 312).
?DOC(
" Returns a bitboard with the nth rank occupied of the provided bitboard.\n"
" Ranks are indexed from 0 to height - 1, and start from the north side of the board.\n"
"\n"
" i.e.\n"
" ```\n"
" 000\n"
" rank(Bitboard(3, 3, 1)) --> 111\n"
" 000\n"
" ````\n"
).
-spec rank(bitboard(), integer()) -> {ok, bitboard()} | {error, binary()}.
rank(Bitboard, Rank_no) ->
gleam@bool:guard(
Rank_no < 0,
{error, <<"rank_no must be positive"/utf8>>},
fun() ->
gleam@bool:guard(
Rank_no >= erlang:element(3, Bitboard),
{error, <<"rank_no must be less than bitboard.height"/utf8>>},
fun() ->
First_rank = first_rank(Bitboard, 0, 0),
Rank = erlang:'bsl'(
erlang:element(4, First_rank),
Rank_no * erlang:element(2, Bitboard)
),
{ok,
begin
_record = Bitboard,
{bitboard,
erlang:element(2, _record),
erlang:element(3, _record),
Rank}
end}
end
)
end
).
-file("src/bibi/bitboard.gleam", 325).
?DOC(" File Masks\n").
-spec first_file(bitboard(), integer(), integer()) -> bitboard().
first_file(Bitboard, Counter, Val) ->
case Counter >= erlang:element(3, Bitboard) of
true ->
_record = Bitboard,
{bitboard,
erlang:element(2, _record),
erlang:element(3, _record),
Val};
false ->
first_file(
Bitboard,
Counter + 1,
erlang:'bor'(
erlang:'bsl'(1, Counter * erlang:element(2, Bitboard)),
Val
)
)
end.
-file("src/bibi/bitboard.gleam", 347).
?DOC(
" Returns a bitboard with the nth file occupied of the provided bitboard\n"
" Files are indexed from 0 to width - 1, and start from the west side of the board\n"
"\n"
" i.e.\n"
" ```\n"
" 010\n"
" file(Bitboard(3, 3, 1)) --> 010\n"
" 010\n"
" ````\n"
).
-spec file(bitboard(), integer()) -> {ok, bitboard()} | {error, binary()}.
file(Bitboard, File_no) ->
gleam@bool:guard(
File_no < 0,
{error, <<"file_no must be positive"/utf8>>},
fun() ->
gleam@bool:guard(
File_no >= erlang:element(2, Bitboard),
{error, <<"file_no must be less than bitboard.width"/utf8>>},
fun() ->
First_file = first_file(Bitboard, 0, 0),
File = erlang:'bsl'(erlang:element(4, First_file), File_no),
{ok,
begin
_record = Bitboard,
{bitboard,
erlang:element(2, _record),
erlang:element(3, _record),
File}
end}
end
)
end
).
-file("src/bibi/bitboard.gleam", 359).
-spec diagonal_from_south_west(bitboard()) -> bitboard().
diagonal_from_south_west(B) ->
Length = gleam@int:min(erlang:element(2, B), erlang:element(3, B)),
Val = begin
_pipe = gleam@list:range(0, Length - 1),
gleam@list:fold(
_pipe,
0,
fun(Acc, I) ->
New_bit = erlang:'bsl'(1, (erlang:element(2, B) * I) + I),
erlang:'bor'(Acc, New_bit)
end
)
end,
_record = B,
{bitboard, erlang:element(2, _record), erlang:element(3, _record), Val}.
-file("src/bibi/bitboard.gleam", 370).
-spec antidiagonal_from_south_east(bitboard()) -> bitboard().
antidiagonal_from_south_east(B) ->
Length = gleam@int:min(erlang:element(2, B), erlang:element(3, B)),
Seed = erlang:'bsl'(1, erlang:element(2, B) - 1),
Val = begin
_pipe = gleam@list:range(0, Length - 1),
gleam@list:fold(
_pipe,
0,
fun(Acc, _) ->
Acc@1 = erlang:'bsl'(Acc, erlang:element(2, B) - 1),
erlang:'bor'(Acc@1, Seed)
end
)
end,
B@1 = begin
_record = B,
{bitboard, erlang:element(2, _record), erlang:element(3, _record), Val}
end,
B@1.
-file("src/bibi/bitboard.gleam", 490).
?DOC(
" Perfroms the `and` operation on two bitboards and returns a new bitboard.\n"
" If a square is occupied on both bitboards, it will be occupied in the\n"
" resulting bitboard. Both bitboards must have the same width and height.\n"
" ```\n"
" 010 000 000\n"
" 010 and 111 --> 010\n"
" 010 000 000\n"
" ```\n"
).
-spec bitboard_and(bitboard(), bitboard()) -> {ok, bitboard()} |
{error, binary()}.
bitboard_and(Bitboard_1, Bitboard_2) ->
case validate_equal_dimensions(Bitboard_1, Bitboard_2) of
{error, Err} ->
{error, Err};
{ok, _} ->
{ok,
begin
_record = Bitboard_1,
{bitboard,
erlang:element(2, _record),
erlang:element(3, _record),
erlang:'band'(
erlang:element(4, Bitboard_1),
erlang:element(4, Bitboard_2)
)}
end}
end.
-file("src/bibi/bitboard.gleam", 514).
?DOC(
" Perfroms the `or` operation on two bitboards and returns a new bitboard.\n"
" If a square is occupied on both bitboards, it will be occupied in the\n"
" resulting bitboard. Both bitboards must have the same width and height.\n"
" ```\n"
" 010 000 010\n"
" 010 and 111 --> 111\n"
" 010 000 010\n"
" ```\n"
).
-spec bitboard_or(bitboard(), bitboard()) -> {ok, bitboard()} |
{error, binary()}.
bitboard_or(Bitboard_1, Bitboard_2) ->
case validate_equal_dimensions(Bitboard_1, Bitboard_2) of
{error, Err} ->
{error, Err};
{ok, _} ->
{ok,
begin
_record = Bitboard_1,
{bitboard,
erlang:element(2, _record),
erlang:element(3, _record),
erlang:'bor'(
erlang:element(4, Bitboard_1),
erlang:element(4, Bitboard_2)
)}
end}
end.
-file("src/bibi/bitboard.gleam", 536).
?DOC(
" Performs the `not` operation on a bitboard. All occupied squares will become unoccupied,\n"
" and vice versa.\n"
"\n"
" i.e.\n"
" ```\n"
" 010 101\n"
" 101 -> 010\n"
" 010 101\n"
" ```\n"
).
-spec bitboard_not(bitboard()) -> bitboard().
bitboard_not(Bitboard) ->
Full_board = erlang:'bsl'(
1,
erlang:element(2, Bitboard) * erlang:element(3, Bitboard)
)
- 1,
Val = erlang:'bxor'(erlang:element(4, Bitboard), Full_board),
_record = Bitboard,
{bitboard, erlang:element(2, _record), erlang:element(3, _record), Val}.
-file("src/bibi/bitboard.gleam", 552).
?DOC(
" Shifts the entire board towards the north by `i`\n"
"\n"
" i.e. shift_north by 1\n"
" ````\n"
" 100 100\n"
" 100 -> 100\n"
" 100 000\n"
" ````\n"
).
-spec shift_north(bitboard(), integer()) -> {ok, bitboard()} | {error, binary()}.
shift_north(Bitboard, I) ->
gleam@bool:guard(
I =:= 0,
{ok, Bitboard},
fun() ->
gleam@bool:guard(
I < 0,
{error, <<"shift_north by must be >= 0"/utf8>>},
fun() ->
Val = begin
_pipe = erlang:element(4, Bitboard),
_pipe@1 = erlang:'bsl'(
_pipe,
I * erlang:element(2, Bitboard)
),
erlang:'band'(_pipe@1, int_full_mask(Bitboard))
end,
{ok,
begin
_record = Bitboard,
{bitboard,
erlang:element(2, _record),
erlang:element(3, _record),
Val}
end}
end
)
end
).
-file("src/bibi/bitboard.gleam", 570).
?DOC(
" Shifts the entire board towards the south by `i`\n"
"\n"
" i.e. shift_south by 1\n"
" ````\n"
" 100 000\n"
" 100 -> 100\n"
" 100 100\n"
" ````\n"
).
-spec shift_south(bitboard(), integer()) -> {ok, bitboard()} | {error, binary()}.
shift_south(Bitboard, I) ->
gleam@bool:guard(
I =:= 0,
{ok, Bitboard},
fun() ->
gleam@bool:guard(
I < 0,
{error, <<"shift_south by must be >= 0"/utf8>>},
fun() ->
Val = begin
_pipe = erlang:element(4, Bitboard),
erlang:'bsr'(_pipe, I * erlang:element(2, Bitboard))
end,
{ok,
begin
_record = Bitboard,
{bitboard,
erlang:element(2, _record),
erlang:element(3, _record),
Val}
end}
end
)
end
).
-file("src/bibi/bitboard.gleam", 588).
?DOC(
" Shifts the entire board towards the west by `i`. Note that westwards\n"
" shifts will result in westmost occupied squares to be removed completely\n"
"\n"
" i.e. shift_west by 1\n"
" ````\n"
" 111 110\n"
" 000 -> 000\n"
" 000 000\n"
" ````\n"
).
-spec shift_west(bitboard(), integer()) -> {ok, bitboard()} | {error, binary()}.
shift_west(Bitboard, I) ->
gleam@bool:guard(
I =:= 0,
{ok, Bitboard},
fun() ->
gleam@bool:guard(
I < 0,
{error, <<"shift_west by must be >= 0"/utf8>>},
fun() ->
gleam@bool:guard(
I >= erlang:element(2, Bitboard),
{error,
<<"shift_west by must be < bitboard.width"/utf8>>},
fun() ->
Mask = begin
_pipe = gleam@list:range(0, I - 1),
gleam@list:fold(
_pipe,
0,
fun(M, I@1) ->
_assert_subject = file(Bitboard, I@1),
{ok, R} = case _assert_subject of
{ok, _} -> _assert_subject;
_assert_fail ->
erlang:error(
#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
value => _assert_fail,
module => <<"bibi/bitboard"/utf8>>,
function => <<"shift_west"/utf8>>,
line => 599}
)
end,
erlang:'bor'(M, erlang:element(4, R))
end
)
end,
Updated_val = erlang:element(4, Bitboard) - erlang:'band'(
Mask,
erlang:element(4, Bitboard)
),
Val = begin
_pipe@1 = Updated_val,
erlang:'bsr'(_pipe@1, I)
end,
{ok,
begin
_record = Bitboard,
{bitboard,
erlang:element(2, _record),
erlang:element(3, _record),
Val}
end}
end
)
end
)
end
).
-file("src/bibi/bitboard.gleam", 616).
?DOC(
" Shifts the entire board towards the east by `i`. Note that eastwards\n"
" shifts will result in eastmost occupied squares to be removed completely\n"
"\n"
" i.e. shift_east by 1\n"
" ````\n"
" 111 011\n"
" 000 -> 000\n"
" 000 000\n"
" ````\n"
).
-spec shift_east(bitboard(), integer()) -> {ok, bitboard()} | {error, binary()}.
shift_east(Bitboard, I) ->
gleam@bool:guard(
I =:= 0,
{ok, Bitboard},
fun() ->
gleam@bool:guard(
I < 0,
{error, <<"shift_east by must be >= 0"/utf8>>},
fun() ->
gleam@bool:guard(
I >= erlang:element(2, Bitboard),
{error,
<<"shift_east by must be < bitboard.width"/utf8>>},
fun() ->
Mask = begin
_pipe = gleam@list:range(
erlang:element(2, Bitboard) - 1,
erlang:element(2, Bitboard) - I
),
gleam@list:fold(
_pipe,
0,
fun(M, I@1) ->
_assert_subject = file(Bitboard, I@1),
{ok, R} = case _assert_subject of
{ok, _} -> _assert_subject;
_assert_fail ->
erlang:error(
#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
value => _assert_fail,
module => <<"bibi/bitboard"/utf8>>,
function => <<"shift_east"/utf8>>,
line => 627}
)
end,
erlang:'bor'(M, erlang:element(4, R))
end
)
end,
Updated_val = erlang:element(4, Bitboard) - erlang:'band'(
Mask,
erlang:element(4, Bitboard)
),
Val = begin
_pipe@1 = Updated_val,
erlang:'bsl'(_pipe@1, I)
end,
{ok,
begin
_record = Bitboard,
{bitboard,
erlang:element(2, _record),
erlang:element(3, _record),
Val}
end}
end
)
end
)
end
).
-file("src/bibi/bitboard.gleam", 410).
?DOC(
" Diagonals are made up of squares that touch at thr corners, and stretch from the\n"
" south eastern corner and towards the north western corner.\n"
"\n"
" In rectangular bitboards, the diagonals will appear as follows\n"
"\n"
" ```\n"
" 0010\n"
" 0100\n"
" 1000\n"
" ```\n"
"\n"
" Diagonals are indexed in the `width + rank - file`. In a bitboard of width 3 and\n"
" height 4, the diagonals will be indexed as\n"
" ```\n"
" 5 . .\n"
" 4 . .\n"
" 3 . .\n"
" 2 1 0\n"
" ```\n"
"\n"
" A diagonal of index 3 in the above bitboard will look like this\n"
" ```\n"
" 001\n"
" 010\n"
" 100\n"
" 000\n"
" ```\n"
).
-spec diagonal(bitboard(), integer()) -> {ok, bitboard()} | {error, binary()}.
diagonal(Bitboard, Diagonal_no) ->
Max_diagonal_no = (erlang:element(2, Bitboard) + erlang:element(3, Bitboard))
- 2,
gleam@bool:guard(
Diagonal_no < 0,
{error, <<"diagonal_no must be positive"/utf8>>},
fun() ->
gleam@bool:guard(
Diagonal_no > Max_diagonal_no,
{error,
<<"diagonal_no must be less than bitboard.width + bitboard.height - 1"/utf8>>},
fun() ->
Main_diagonal = diagonal_from_south_west(Bitboard),
case {Diagonal_no < erlang:element(2, Bitboard),
erlang:element(2, Bitboard) < erlang:element(
3,
Bitboard
)} of
{true, true} ->
shift_south(
Main_diagonal,
(erlang:element(2, Bitboard) - Diagonal_no) - 1
);
{true, false} ->
shift_east(
Main_diagonal,
(erlang:element(2, Bitboard) - Diagonal_no) - 1
);
{false, true} ->
shift_north(
Main_diagonal,
(Diagonal_no - erlang:element(2, Bitboard)) + 1
);
{false, false} ->
shift_west(
Main_diagonal,
(Diagonal_no - erlang:element(2, Bitboard)) + 1
)
end
end
)
end
).
-file("src/bibi/bitboard.gleam", 455).
?DOC(
" Antidiagonals are made up of squares that touch at thr corners, and stretch from the\n"
" south eastern corner and towards the north western corner.\n"
"\n"
" In rectangular bitboards, the anti-diagonals will appear as follows\n"
"\n"
" ```\n"
" 1000\n"
" 0100\n"
" 0010\n"
" ```\n"
"\n"
" Antidiagonals are indexed in the `rank + file`. In a bitboard of width 3 and\n"
" height 4, the anti-diagonals will be indexed as\n"
" ```\n"
" . . 5\n"
" . . 4\n"
" . . 3\n"
" 0 1 2\n"
" ```\n"
"\n"
" A anti-diagonal of index 3 in the above bitboard will look like this\n"
" ```\n"
" 100\n"
" 010\n"
" 001\n"
" 000\n"
" ```\n"
).
-spec antidiagonal(bitboard(), integer()) -> {ok, bitboard()} |
{error, binary()}.
antidiagonal(Bitboard, Antidiagonal_no) ->
Max_antidiagonal_no = (erlang:element(2, Bitboard) + erlang:element(
3,
Bitboard
))
- 2,
gleam@bool:guard(
Antidiagonal_no < 0,
{error, <<"antidiagonal_no must be positive"/utf8>>},
fun() ->
gleam@bool:guard(
Antidiagonal_no > Max_antidiagonal_no,
{error,
<<"antidiagonal_no must be less than bitboard.width + bitboard.height - 1"/utf8>>},
fun() ->
Main_diagonal = antidiagonal_from_south_east(Bitboard),
case {Antidiagonal_no < erlang:element(2, Bitboard),
erlang:element(2, Bitboard) < erlang:element(
3,
Bitboard
)} of
{true, true} ->
shift_south(
Main_diagonal,
(erlang:element(2, Bitboard) - Antidiagonal_no)
- 1
);
{true, false} ->
shift_west(
Main_diagonal,
(erlang:element(2, Bitboard) - Antidiagonal_no)
- 1
);
{false, true} ->
shift_north(
Main_diagonal,
(Antidiagonal_no - erlang:element(2, Bitboard))
+ 1
);
{false, false} ->
shift_east(
Main_diagonal,
(Antidiagonal_no - erlang:element(2, Bitboard))
+ 1
)
end
end
)
end
).
-file("src/bibi/bitboard.gleam", 643).
?DOC(
" Flips a bitboard vertically\n"
"\n"
" i.e\n"
" ````\n"
" 111 000\n"
" 000 -> 000\n"
" 000 111\n"
" ````\n"
).
-spec flip_vertically(bitboard()) -> bitboard().
flip_vertically(Bitboard) ->
_pipe = gleam@list:range(0, erlang:element(3, Bitboard) - 1),
gleam@list:fold(
_pipe,
begin
_record = Bitboard,
{bitboard,
erlang:element(2, _record),
erlang:element(3, _record),
0}
end,
fun(B, I) ->
_assert_subject = rank(Bitboard, I),
{ok, Rank_mask} = case _assert_subject of
{ok, _} -> _assert_subject;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
value => _assert_fail,
module => <<"bibi/bitboard"/utf8>>,
function => <<"flip_vertically"/utf8>>,
line => 646})
end,
_assert_subject@1 = bitboard_and(Bitboard, Rank_mask),
{ok, Rank} = case _assert_subject@1 of
{ok, _} -> _assert_subject@1;
_assert_fail@1 ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
value => _assert_fail@1,
module => <<"bibi/bitboard"/utf8>>,
function => <<"flip_vertically"/utf8>>,
line => 647})
end,
_assert_subject@2 = shift_south(Rank, I),
{ok, Rank@1} = case _assert_subject@2 of
{ok, _} -> _assert_subject@2;
_assert_fail@2 ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
value => _assert_fail@2,
module => <<"bibi/bitboard"/utf8>>,
function => <<"flip_vertically"/utf8>>,
line => 648})
end,
_assert_subject@3 = shift_north(
Rank@1,
(erlang:element(3, Bitboard) - I) - 1
),
{ok, Rank@2} = case _assert_subject@3 of
{ok, _} -> _assert_subject@3;
_assert_fail@3 ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
value => _assert_fail@3,
module => <<"bibi/bitboard"/utf8>>,
function => <<"flip_vertically"/utf8>>,
line => 649})
end,
_assert_subject@4 = bitboard_or(B, Rank@2),
{ok, Updated_bitboard} = case _assert_subject@4 of
{ok, _} -> _assert_subject@4;
_assert_fail@4 ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
value => _assert_fail@4,
module => <<"bibi/bitboard"/utf8>>,
function => <<"flip_vertically"/utf8>>,
line => 650})
end,
Updated_bitboard
end
).
-file("src/bibi/bitboard.gleam", 663).
?DOC(
" Flips a bitboard horizontally\n"
"\n"
" i.e\n"
" ````\n"
" 100 001\n"
" 100 -> 001\n"
" 100 001\n"
" ````\n"
).
-spec flip_horizontally(bitboard()) -> bitboard().
flip_horizontally(Bitboard) ->
_pipe = gleam@list:range(0, erlang:element(2, Bitboard) - 1),
gleam@list:fold(
_pipe,
begin
_record = Bitboard,
{bitboard,
erlang:element(2, _record),
erlang:element(3, _record),
0}
end,
fun(B, I) ->
_assert_subject = file(Bitboard, I),
{ok, File_mask} = case _assert_subject of
{ok, _} -> _assert_subject;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
value => _assert_fail,
module => <<"bibi/bitboard"/utf8>>,
function => <<"flip_horizontally"/utf8>>,
line => 666})
end,
_assert_subject@1 = bitboard_and(Bitboard, File_mask),
{ok, File} = case _assert_subject@1 of
{ok, _} -> _assert_subject@1;
_assert_fail@1 ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
value => _assert_fail@1,
module => <<"bibi/bitboard"/utf8>>,
function => <<"flip_horizontally"/utf8>>,
line => 667})
end,
_assert_subject@2 = shift_west(File, I),
{ok, File@1} = case _assert_subject@2 of
{ok, _} -> _assert_subject@2;
_assert_fail@2 ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
value => _assert_fail@2,
module => <<"bibi/bitboard"/utf8>>,
function => <<"flip_horizontally"/utf8>>,
line => 668})
end,
_assert_subject@3 = shift_east(
File@1,
(erlang:element(2, Bitboard) - I) - 1
),
{ok, File@2} = case _assert_subject@3 of
{ok, _} -> _assert_subject@3;
_assert_fail@3 ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
value => _assert_fail@3,
module => <<"bibi/bitboard"/utf8>>,
function => <<"flip_horizontally"/utf8>>,
line => 669})
end,
_assert_subject@4 = bitboard_or(B, File@2),
{ok, Updated_bitboard} = case _assert_subject@4 of
{ok, _} -> _assert_subject@4;
_assert_fail@4 ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
value => _assert_fail@4,
module => <<"bibi/bitboard"/utf8>>,
function => <<"flip_horizontally"/utf8>>,
line => 670})
end,
Updated_bitboard
end
).