-module(fen). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function]). -export([to_string/1, parse_board/1, to_board/1, from_string/1]). -export_type([castling_status/0, fen/0]). -type castling_status() :: {castling_status, boolean(), boolean(), boolean(), boolean()}. -type fen() :: {fen, board:board_bb(), color:color(), castling_status(), gleam@option:option(position:position()), integer(), integer()}. -spec piece_to_fen_string(piece:piece()) -> binary(). piece_to_fen_string(Piece) -> case Piece of {piece, white, king} -> <<"K"/utf8>>; {piece, white, queen} -> <<"Q"/utf8>>; {piece, white, rook} -> <<"R"/utf8>>; {piece, white, bishop} -> <<"B"/utf8>>; {piece, white, knight} -> <<"N"/utf8>>; {piece, white, pawn} -> <<"P"/utf8>>; {piece, black, king} -> <<"k"/utf8>>; {piece, black, queen} -> <<"q"/utf8>>; {piece, black, rook} -> <<"r"/utf8>>; {piece, black, bishop} -> <<"b"/utf8>>; {piece, black, knight} -> <<"n"/utf8>>; {piece, black, pawn} -> <<"p"/utf8>> end. -spec board_to_fen_string(board:board_bb()) -> binary(). board_to_fen_string(Board) -> Board_string = gleam@list:fold( [{position, a, eight}, {position, b, eight}, {position, c, eight}, {position, d, eight}, {position, e, eight}, {position, f, eight}, {position, g, eight}, {position, h, eight}, {position, a, seven}, {position, b, seven}, {position, c, seven}, {position, d, seven}, {position, e, seven}, {position, f, seven}, {position, g, seven}, {position, h, seven}, {position, a, six}, {position, b, six}, {position, c, six}, {position, d, six}, {position, e, six}, {position, f, six}, {position, g, six}, {position, h, six}, {position, a, five}, {position, b, five}, {position, c, five}, {position, d, five}, {position, e, five}, {position, f, five}, {position, g, five}, {position, h, five}, {position, a, four}, {position, b, four}, {position, c, four}, {position, d, four}, {position, e, four}, {position, f, four}, {position, g, four}, {position, h, four}, {position, a, three}, {position, b, three}, {position, c, three}, {position, d, three}, {position, e, three}, {position, f, three}, {position, g, three}, {position, h, three}, {position, a, two}, {position, b, two}, {position, c, two}, {position, d, two}, {position, e, two}, {position, f, two}, {position, g, two}, {position, h, two}, {position, a, one}, {position, b, one}, {position, c, one}, {position, d, one}, {position, e, one}, {position, f, one}, {position, g, one}, {position, h, one}], <<""/utf8>>, fun(Acc, Pos) -> Piece = board:get_piece_at_position(Board, Pos), Acc@1 = case Piece of none -> Last_char = gleam@string:last(Acc), case Last_char of {error, nil} -> gleam@string:append(Acc, <<"1"/utf8>>); {ok, <<"/"/utf8>>} -> gleam@string:append(Acc, <<"1"/utf8>>); {ok, <<"1"/utf8>>} -> gleam@string:append( gleam@string:drop_right(Acc, 1), <<"2"/utf8>> ); {ok, <<"2"/utf8>>} -> gleam@string:append( gleam@string:drop_right(Acc, 1), <<"3"/utf8>> ); {ok, <<"3"/utf8>>} -> gleam@string:append( gleam@string:drop_right(Acc, 1), <<"4"/utf8>> ); {ok, <<"4"/utf8>>} -> gleam@string:append( gleam@string:drop_right(Acc, 1), <<"5"/utf8>> ); {ok, <<"5"/utf8>>} -> gleam@string:append( gleam@string:drop_right(Acc, 1), <<"6"/utf8>> ); {ok, <<"6"/utf8>>} -> gleam@string:append( gleam@string:drop_right(Acc, 1), <<"7"/utf8>> ); {ok, <<"7"/utf8>>} -> gleam@string:append( gleam@string:drop_right(Acc, 1), <<"8"/utf8>> ); {ok, <<"8"/utf8>>} -> (erlang:error(#{gleam_error => panic, message => <<"panic expression evaluated"/utf8>>, module => <<"fen"/utf8>>, function => <<"board_to_fen_string"/utf8>>, line => 150}))( <<"Unable to encode BoardBB to FEN string"/utf8>> ); {ok, _} -> gleam@string:append(Acc, <<"1"/utf8>>) end; {some, Piece@1} -> Piece_string = piece_to_fen_string(Piece@1), gleam@string:append(Acc, Piece_string) end, Acc@2 = case Pos of {position, h, one} -> Acc@1; {position, h, _} -> gleam@string:append(Acc@1, <<"/"/utf8>>); _ -> Acc@1 end, Acc@2 end ), Board_string. -spec turn_to_fen_string(color:color()) -> binary(). turn_to_fen_string(Turn) -> case Turn of white -> <<"w"/utf8>>; black -> <<"b"/utf8>> end. -spec castling_to_fen_string(castling_status()) -> binary(). castling_to_fen_string(Castling) -> White_kingside_castling = case erlang:element(2, Castling) of true -> <<"K"/utf8>>; false -> <<""/utf8>> end, White_queenside_castling = case erlang:element(3, Castling) of true -> <<"Q"/utf8>>; false -> <<""/utf8>> end, Black_kingside_castling = case erlang:element(4, Castling) of true -> <<"k"/utf8>>; false -> <<""/utf8>> end, Black_queenside_castling = case erlang:element(5, Castling) of true -> <<"q"/utf8>>; false -> <<""/utf8>> end, Castling_string = gleam@string:join( [White_kingside_castling, White_queenside_castling, Black_kingside_castling, Black_queenside_castling], <<""/utf8>> ), case Castling_string of <<""/utf8>> -> <<"-"/utf8>>; _ -> Castling_string end. -spec en_passant_to_fen_string(gleam@option:option(position:position())) -> binary(). en_passant_to_fen_string(En_passant) -> case En_passant of none -> <<"-"/utf8>>; {some, Pos} -> File_string = position:file_to_string(erlang:element(2, Pos)), Rank_string = position:rank_to_string(erlang:element(3, Pos)), gleam@string:join([File_string, Rank_string], <<""/utf8>>) end. -spec to_string(fen()) -> binary(). to_string(Fen) -> Board_string = board_to_fen_string(erlang:element(2, Fen)), Turn_string = turn_to_fen_string(erlang:element(3, Fen)), Castling_string = castling_to_fen_string(erlang:element(4, Fen)), En_passant_string = en_passant_to_fen_string(erlang:element(5, Fen)), Halfmove_string = gleam@int:to_string(erlang:element(6, Fen)), Fullmove_string = gleam@int:to_string(erlang:element(7, Fen)), Fen_string = gleam@string:join( [Board_string, Turn_string, Castling_string, En_passant_string, Halfmove_string, Fullmove_string], <<" "/utf8>> ), Fen_string. -spec expand_rank(list(binary())) -> list(binary()). expand_rank(Rank) -> Accumulator = [], gleam@list:fold(Rank, Accumulator, fun(Acc, Part) -> case Part of <<"1"/utf8>> -> gleam@list:append(Acc, [<<""/utf8>>]); <<"2"/utf8>> -> gleam@list:append(Acc, [<<""/utf8>>, <<""/utf8>>]); <<"3"/utf8>> -> gleam@list:append( Acc, [<<""/utf8>>, <<""/utf8>>, <<""/utf8>>] ); <<"4"/utf8>> -> gleam@list:append( Acc, [<<""/utf8>>, <<""/utf8>>, <<""/utf8>>, <<""/utf8>>] ); <<"5"/utf8>> -> gleam@list:append( Acc, [<<""/utf8>>, <<""/utf8>>, <<""/utf8>>, <<""/utf8>>, <<""/utf8>>] ); <<"6"/utf8>> -> gleam@list:append( Acc, [<<""/utf8>>, <<""/utf8>>, <<""/utf8>>, <<""/utf8>>, <<""/utf8>>, <<""/utf8>>] ); <<"7"/utf8>> -> gleam@list:append( Acc, [<<""/utf8>>, <<""/utf8>>, <<""/utf8>>, <<""/utf8>>, <<""/utf8>>, <<""/utf8>>, <<""/utf8>>] ); <<"8"/utf8>> -> gleam@list:append( Acc, [<<""/utf8>>, <<""/utf8>>, <<""/utf8>>, <<""/utf8>>, <<""/utf8>>, <<""/utf8>>, <<""/utf8>>, <<""/utf8>>] ); <<"K"/utf8>> -> gleam@list:append(Acc, [<<"K"/utf8>>]); <<"Q"/utf8>> -> gleam@list:append(Acc, [<<"Q"/utf8>>]); <<"R"/utf8>> -> gleam@list:append(Acc, [<<"R"/utf8>>]); <<"B"/utf8>> -> gleam@list:append(Acc, [<<"B"/utf8>>]); <<"N"/utf8>> -> gleam@list:append(Acc, [<<"N"/utf8>>]); <<"P"/utf8>> -> gleam@list:append(Acc, [<<"P"/utf8>>]); <<"k"/utf8>> -> gleam@list:append(Acc, [<<"k"/utf8>>]); <<"q"/utf8>> -> gleam@list:append(Acc, [<<"q"/utf8>>]); <<"r"/utf8>> -> gleam@list:append(Acc, [<<"r"/utf8>>]); <<"b"/utf8>> -> gleam@list:append(Acc, [<<"b"/utf8>>]); <<"n"/utf8>> -> gleam@list:append(Acc, [<<"n"/utf8>>]); <<"p"/utf8>> -> gleam@list:append(Acc, [<<"p"/utf8>>]); _ -> gleam@list:append(Acc, [Part]) end end). -spec parse_board(binary()) -> board:board_bb(). parse_board(Board_string) -> List_of_ranks_as_strings = gleam@string:split(Board_string, <<"/"/utf8>>), Accumulator = {board_bb, {bitboard, 0}, {bitboard, 0}, {bitboard, 0}, {bitboard, 0}, {bitboard, 0}, {bitboard, 0}, {bitboard, 0}, {bitboard, 0}, {bitboard, 0}, {bitboard, 0}, {bitboard, 0}, {bitboard, 0}}, gleam@list:index_fold( List_of_ranks_as_strings, Accumulator, fun(Acc, Rank_as_string, Rank_index) -> Rank_index@1 = position:int_to_rank(7 - Rank_index), Rank_parts = gleam@string:to_graphemes(Rank_as_string), Expanded_rank = expand_rank(Rank_parts), gleam@list:index_fold( Expanded_rank, Acc, fun(Acc@1, Square, File_index) -> File_index@1 = position:int_to_file(File_index), case Square of <<""/utf8>> -> Acc@1; <<"K"/utf8>> -> New_white_king_bitboard = board:from_position( {position, File_index@1, Rank_index@1} ), {board_bb, erlang:element(2, Acc@1), erlang:element(3, Acc@1), erlang:element(4, Acc@1), erlang:element(5, Acc@1), erlang:element(6, Acc@1), erlang:element(7, Acc@1), bitboard:'or'( erlang:element(8, Acc@1), New_white_king_bitboard ), erlang:element(9, Acc@1), erlang:element(10, Acc@1), erlang:element(11, Acc@1), erlang:element(12, Acc@1), erlang:element(13, Acc@1)}; <<"Q"/utf8>> -> New_white_queen_bitboard = board:from_position( {position, File_index@1, Rank_index@1} ), {board_bb, erlang:element(2, Acc@1), erlang:element(3, Acc@1), erlang:element(4, Acc@1), erlang:element(5, Acc@1), erlang:element(6, Acc@1), erlang:element(7, Acc@1), erlang:element(8, Acc@1), bitboard:'or'( erlang:element(9, Acc@1), New_white_queen_bitboard ), erlang:element(10, Acc@1), erlang:element(11, Acc@1), erlang:element(12, Acc@1), erlang:element(13, Acc@1)}; <<"R"/utf8>> -> New_white_rook_bitboard = board:from_position( {position, File_index@1, Rank_index@1} ), {board_bb, erlang:element(2, Acc@1), erlang:element(3, Acc@1), erlang:element(4, Acc@1), erlang:element(5, Acc@1), erlang:element(6, Acc@1), erlang:element(7, Acc@1), erlang:element(8, Acc@1), erlang:element(9, Acc@1), bitboard:'or'( erlang:element(10, Acc@1), New_white_rook_bitboard ), erlang:element(11, Acc@1), erlang:element(12, Acc@1), erlang:element(13, Acc@1)}; <<"B"/utf8>> -> New_white_bishop_bitboard = board:from_position( {position, File_index@1, Rank_index@1} ), {board_bb, erlang:element(2, Acc@1), erlang:element(3, Acc@1), erlang:element(4, Acc@1), erlang:element(5, Acc@1), erlang:element(6, Acc@1), erlang:element(7, Acc@1), erlang:element(8, Acc@1), erlang:element(9, Acc@1), erlang:element(10, Acc@1), bitboard:'or'( erlang:element(11, Acc@1), New_white_bishop_bitboard ), erlang:element(12, Acc@1), erlang:element(13, Acc@1)}; <<"N"/utf8>> -> New_white_knight_bitboard = board:from_position( {position, File_index@1, Rank_index@1} ), {board_bb, erlang:element(2, Acc@1), erlang:element(3, Acc@1), erlang:element(4, Acc@1), erlang:element(5, Acc@1), erlang:element(6, Acc@1), erlang:element(7, Acc@1), erlang:element(8, Acc@1), erlang:element(9, Acc@1), erlang:element(10, Acc@1), erlang:element(11, Acc@1), bitboard:'or'( erlang:element(12, Acc@1), New_white_knight_bitboard ), erlang:element(13, Acc@1)}; <<"P"/utf8>> -> New_white_pawn_bitboard = board:from_position( {position, File_index@1, Rank_index@1} ), {board_bb, erlang:element(2, Acc@1), erlang:element(3, Acc@1), erlang:element(4, Acc@1), erlang:element(5, Acc@1), erlang:element(6, Acc@1), erlang:element(7, Acc@1), erlang:element(8, Acc@1), erlang:element(9, Acc@1), erlang:element(10, Acc@1), erlang:element(11, Acc@1), erlang:element(12, Acc@1), bitboard:'or'( erlang:element(13, Acc@1), New_white_pawn_bitboard )}; <<"k"/utf8>> -> New_black_king_bitboard = board:from_position( {position, File_index@1, Rank_index@1} ), {board_bb, bitboard:'or'( erlang:element(2, Acc@1), New_black_king_bitboard ), erlang:element(3, Acc@1), erlang:element(4, Acc@1), erlang:element(5, Acc@1), erlang:element(6, Acc@1), erlang:element(7, Acc@1), erlang:element(8, Acc@1), erlang:element(9, Acc@1), erlang:element(10, Acc@1), erlang:element(11, Acc@1), erlang:element(12, Acc@1), erlang:element(13, Acc@1)}; <<"q"/utf8>> -> New_black_queen_bitboard = board:from_position( {position, File_index@1, Rank_index@1} ), {board_bb, erlang:element(2, Acc@1), bitboard:'or'( erlang:element(3, Acc@1), New_black_queen_bitboard ), erlang:element(4, Acc@1), erlang:element(5, Acc@1), erlang:element(6, Acc@1), erlang:element(7, Acc@1), erlang:element(8, Acc@1), erlang:element(9, Acc@1), erlang:element(10, Acc@1), erlang:element(11, Acc@1), erlang:element(12, Acc@1), erlang:element(13, Acc@1)}; <<"r"/utf8>> -> New_black_rook_bitboard = board:from_position( {position, File_index@1, Rank_index@1} ), {board_bb, erlang:element(2, Acc@1), erlang:element(3, Acc@1), bitboard:'or'( erlang:element(4, Acc@1), New_black_rook_bitboard ), erlang:element(5, Acc@1), erlang:element(6, Acc@1), erlang:element(7, Acc@1), erlang:element(8, Acc@1), erlang:element(9, Acc@1), erlang:element(10, Acc@1), erlang:element(11, Acc@1), erlang:element(12, Acc@1), erlang:element(13, Acc@1)}; <<"b"/utf8>> -> New_black_bishop_bitboard = board:from_position( {position, File_index@1, Rank_index@1} ), {board_bb, erlang:element(2, Acc@1), erlang:element(3, Acc@1), erlang:element(4, Acc@1), bitboard:'or'( erlang:element(5, Acc@1), New_black_bishop_bitboard ), erlang:element(6, Acc@1), erlang:element(7, Acc@1), erlang:element(8, Acc@1), erlang:element(9, Acc@1), erlang:element(10, Acc@1), erlang:element(11, Acc@1), erlang:element(12, Acc@1), erlang:element(13, Acc@1)}; <<"n"/utf8>> -> New_black_knight_bitboard = board:from_position( {position, File_index@1, Rank_index@1} ), {board_bb, erlang:element(2, Acc@1), erlang:element(3, Acc@1), erlang:element(4, Acc@1), erlang:element(5, Acc@1), bitboard:'or'( erlang:element(6, Acc@1), New_black_knight_bitboard ), erlang:element(7, Acc@1), erlang:element(8, Acc@1), erlang:element(9, Acc@1), erlang:element(10, Acc@1), erlang:element(11, Acc@1), erlang:element(12, Acc@1), erlang:element(13, Acc@1)}; <<"p"/utf8>> -> New_black_pawns_bitboard = board:from_position( {position, File_index@1, Rank_index@1} ), {board_bb, erlang:element(2, Acc@1), erlang:element(3, Acc@1), erlang:element(4, Acc@1), erlang:element(5, Acc@1), erlang:element(6, Acc@1), bitboard:'or'( erlang:element(7, Acc@1), New_black_pawns_bitboard ), erlang:element(8, Acc@1), erlang:element(9, Acc@1), erlang:element(10, Acc@1), erlang:element(11, Acc@1), erlang:element(12, Acc@1), erlang:element(13, Acc@1)}; _ -> erlang:error(#{gleam_error => panic, message => <<"panic expression evaluated"/utf8>>, module => <<"fen"/utf8>>, function => <<"parse_board"/utf8>>, line => 628}) end end ) end ). -spec to_board(binary()) -> board:board_bb(). to_board(Fen) -> Fen_string_parts = gleam@string:split(Fen, <<" "/utf8>>), Parsed_board@1 = case gleam@list:length(Fen_string_parts) =:= 6 of false -> erlang:error(#{gleam_error => panic, message => <<"Invalid FEN string"/utf8>>, module => <<"fen"/utf8>>, function => <<"to_board"/utf8>>, line => 107}); true -> [Board_string | _] = Fen_string_parts, Parsed_board = parse_board(Board_string), Parsed_board end, Parsed_board@1. -spec parse_turn(binary()) -> color:color(). parse_turn(Turn_string) -> case Turn_string of <<"w"/utf8>> -> white; <<"b"/utf8>> -> black; _ -> erlang:error(#{gleam_error => panic, message => <<"Invalid turn string, must be 'w' or 'b'"/utf8>>, module => <<"fen"/utf8>>, function => <<"parse_turn"/utf8>>, line => 674}) end. -spec parse_castling(binary()) -> castling_status(). parse_castling(Castling_string) -> case gleam@string:length(Castling_string) =< 4 of true -> Cs_parts = gleam@string:split(Castling_string, <<""/utf8>>), gleam@list:each(Cs_parts, fun(Part) -> case Part of <<"K"/utf8>> -> nil; <<"Q"/utf8>> -> nil; <<"k"/utf8>> -> nil; <<"q"/utf8>> -> nil; <<"-"/utf8>> -> nil; _ -> erlang:error(#{gleam_error => panic, message => <<"Invalid castling string"/utf8>>, module => <<"fen"/utf8>>, function => <<"parse_castling"/utf8>>, line => 691}) end end), White_queenside_castling = gleam@string:contains( Castling_string, <<"Q"/utf8>> ), White_kingside_castling = gleam@string:contains( Castling_string, <<"K"/utf8>> ), Black_queenside_castling = gleam@string:contains( Castling_string, <<"q"/utf8>> ), Black_kingside_castling = gleam@string:contains( Castling_string, <<"k"/utf8>> ), {castling_status, White_kingside_castling, White_queenside_castling, Black_kingside_castling, Black_queenside_castling}; false -> erlang:error(#{gleam_error => panic, message => <<"Invalid castling string"/utf8>>, module => <<"fen"/utf8>>, function => <<"parse_castling"/utf8>>, line => 707}) end. -spec parse_file(binary()) -> position:file(). parse_file(File_string) -> case File_string of <<"a"/utf8>> -> a; <<"b"/utf8>> -> b; <<"c"/utf8>> -> c; <<"d"/utf8>> -> d; <<"e"/utf8>> -> e; <<"f"/utf8>> -> f; <<"g"/utf8>> -> g; <<"h"/utf8>> -> h; _ -> erlang:error(#{gleam_error => panic, message => <<"Invalid file string"/utf8>>, module => <<"fen"/utf8>>, function => <<"parse_file"/utf8>>, line => 738}) end. -spec parse_rank(binary()) -> position:rank(). parse_rank(Rank_string) -> case Rank_string of <<"1"/utf8>> -> one; <<"2"/utf8>> -> two; <<"3"/utf8>> -> three; <<"4"/utf8>> -> four; <<"5"/utf8>> -> five; <<"6"/utf8>> -> six; <<"7"/utf8>> -> seven; <<"8"/utf8>> -> eight; _ -> erlang:error(#{gleam_error => panic, message => <<"Invalid rank string"/utf8>>, module => <<"fen"/utf8>>, function => <<"parse_rank"/utf8>>, line => 752}) end. -spec parse_en_passant(binary()) -> gleam@option:option(position:position()). parse_en_passant(En_passant_string) -> case En_passant_string of <<"-"/utf8>> -> none; _ -> case gleam@string:length(En_passant_string) =:= 2 of true -> nil; false -> erlang:error(#{gleam_error => panic, message => <<"Invalid en passant string"/utf8>>, module => <<"fen"/utf8>>, function => <<"parse_en_passant"/utf8>>, line => 717}) end, En_passant_parts = gleam@string:split( En_passant_string, <<""/utf8>> ), [File_string, Rank_string] = En_passant_parts, File = parse_file(File_string), Rank = parse_rank(Rank_string), {some, {position, File, Rank}} end. -spec string_to_int(binary()) -> integer(). string_to_int(String) -> case gleam@string:length(String) of 1 -> case String of <<"0"/utf8>> -> 0; <<"1"/utf8>> -> 1; <<"2"/utf8>> -> 2; <<"3"/utf8>> -> 3; <<"4"/utf8>> -> 4; <<"5"/utf8>> -> 5; <<"6"/utf8>> -> 6; <<"7"/utf8>> -> 7; <<"8"/utf8>> -> 8; <<"9"/utf8>> -> 9; _ -> erlang:error(#{gleam_error => panic, message => <<"Invalid halfmove string"/utf8>>, module => <<"fen"/utf8>>, function => <<"string_to_int"/utf8>>, line => 778}) end; 2 -> [Tenths_place_string, Ones_place_string] = gleam@string:split( String, <<""/utf8>> ), Tenths_place = case Tenths_place_string of <<"0"/utf8>> -> 0; <<"1"/utf8>> -> 10; <<"2"/utf8>> -> 20; <<"3"/utf8>> -> 30; <<"4"/utf8>> -> 40; <<"5"/utf8>> -> 50; <<"6"/utf8>> -> 60; <<"7"/utf8>> -> 70; <<"8"/utf8>> -> 80; <<"9"/utf8>> -> 90; _ -> erlang:error(#{gleam_error => panic, message => <<"Invalid halfmove string"/utf8>>, module => <<"fen"/utf8>>, function => <<"string_to_int"/utf8>>, line => 794}) end, Ones_place = case Ones_place_string of <<"0"/utf8>> -> 0; <<"1"/utf8>> -> 1; <<"2"/utf8>> -> 2; <<"3"/utf8>> -> 3; <<"4"/utf8>> -> 4; <<"5"/utf8>> -> 5; <<"6"/utf8>> -> 6; <<"7"/utf8>> -> 7; <<"8"/utf8>> -> 8; <<"9"/utf8>> -> 9; _ -> erlang:error(#{gleam_error => panic, message => <<"Invalid halfmove string"/utf8>>, module => <<"fen"/utf8>>, function => <<"string_to_int"/utf8>>, line => 808}) end, Tenths_place + Ones_place; 3 -> [Hundreds_place_string, Tenths_place_string@1, Ones_place_string@1] = gleam@string:split( String, <<""/utf8>> ), Hundreds_place = case Hundreds_place_string of <<"0"/utf8>> -> 0; <<"1"/utf8>> -> 100; <<"2"/utf8>> -> 200; <<"3"/utf8>> -> 300; <<"4"/utf8>> -> 400; <<"5"/utf8>> -> 500; <<"6"/utf8>> -> 600; <<"7"/utf8>> -> 700; <<"8"/utf8>> -> 800; <<"9"/utf8>> -> 900; _ -> erlang:error(#{gleam_error => panic, message => <<"Invalid halfmove string"/utf8>>, module => <<"fen"/utf8>>, function => <<"string_to_int"/utf8>>, line => 826}) end, Tenths_place@1 = case Tenths_place_string@1 of <<"0"/utf8>> -> 0; <<"1"/utf8>> -> 10; <<"2"/utf8>> -> 20; <<"3"/utf8>> -> 30; <<"4"/utf8>> -> 40; <<"5"/utf8>> -> 50; <<"6"/utf8>> -> 60; <<"7"/utf8>> -> 70; <<"8"/utf8>> -> 80; <<"9"/utf8>> -> 90; _ -> erlang:error(#{gleam_error => panic, message => <<"Invalid halfmove string"/utf8>>, module => <<"fen"/utf8>>, function => <<"string_to_int"/utf8>>, line => 840}) end, Ones_place@1 = case Ones_place_string@1 of <<"0"/utf8>> -> 0; <<"1"/utf8>> -> 1; <<"2"/utf8>> -> 2; <<"3"/utf8>> -> 3; <<"4"/utf8>> -> 4; <<"5"/utf8>> -> 5; <<"6"/utf8>> -> 6; <<"7"/utf8>> -> 7; <<"8"/utf8>> -> 8; <<"9"/utf8>> -> 9; _ -> erlang:error(#{gleam_error => panic, message => <<"Invalid halfmove string"/utf8>>, module => <<"fen"/utf8>>, function => <<"string_to_int"/utf8>>, line => 854}) end, (Hundreds_place + Tenths_place@1) + Ones_place@1; _ -> erlang:error(#{gleam_error => panic, message => <<"Invalid halfmove string"/utf8>>, module => <<"fen"/utf8>>, function => <<"string_to_int"/utf8>>, line => 858}) end. -spec parse_halfmove(binary()) -> integer(). parse_halfmove(Halfmove_string) -> string_to_int(Halfmove_string). -spec parse_fullmove(binary()) -> integer(). parse_fullmove(Fullmove_string) -> string_to_int(Fullmove_string). -spec from_string(binary()) -> fen(). from_string(Fen) -> Fen_string_parts = gleam@string:split(Fen, <<" "/utf8>>), case gleam@list:length(Fen_string_parts) =:= 6 of false -> erlang:error(#{gleam_error => panic, message => <<"Invalid FEN string"/utf8>>, module => <<"fen"/utf8>>, function => <<"from_string"/utf8>>, line => 270}); true -> [Board_string | Rest] = Fen_string_parts, [Turn_string | Rest@1] = Rest, [Castling_string | Rest@2] = Rest@1, [En_passant_string | Rest@3] = Rest@2, [Halfmove_string | Rest@4] = Rest@3, [Fullmove_string | _] = Rest@4, Parsed_board = parse_board(Board_string), Parsed_turn = parse_turn(Turn_string), Parsed_castling = parse_castling(Castling_string), Parsed_en_passant = parse_en_passant(En_passant_string), Parsed_halfmove = parse_halfmove(Halfmove_string), Parsed_fullmove = parse_fullmove(Fullmove_string), Fen@1 = {fen, Parsed_board, Parsed_turn, Parsed_castling, Parsed_en_passant, Parsed_halfmove, Parsed_fullmove}, Fen@1 end.