Current section
Files
Jump to
Current section
Files
src/examples@snake.erl
-module(examples@snake).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/examples/snake.gleam").
-export([main/0]).
-export_type([direction/0, state/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(false).
-type direction() :: up | down | left | right.
-type state() :: {state,
gleam@dict:dict(integer(), integer()),
list(integer()),
integer(),
integer(),
direction(),
integer()}.
-file("src/examples/snake.gleam", 85).
?DOC(false).
-spec make_grid(integer(), integer()) -> gleam@dict:dict(integer(), integer()).
make_grid(Columns, Rows) ->
X = begin
_pipe = gleam@list:range(0, Columns * Rows),
gleam@list:zip(_pipe, gleam@list:repeat(0, Columns * Rows))
end,
D = maps:from_list(X),
case gleam@int:is_even(Rows) of
true ->
gleam@dict:insert(D, ((Rows * Columns) div 2) + (Columns div 2), 1);
false ->
gleam@dict:insert(D, (Rows * Columns) div 2, 1)
end.
-file("src/examples/snake.gleam", 110).
?DOC(false).
-spec handle_input(state()) -> state().
handle_input(State) ->
case {event_ffi:poll(1), erlang:element(6, State)} of
{{some, {ok, {key, K}}}, down} when (erlang:element(2, K) =:= {char,
<<"w"/utf8>>}) orelse (erlang:element(2, K) =:= up_arrow) ->
State;
{{some, {ok, {key, K@1}}}, _} when (erlang:element(2, K@1) =:= {char,
<<"w"/utf8>>}) orelse (erlang:element(2, K@1) =:= up_arrow) ->
{state,
erlang:element(2, State),
erlang:element(3, State),
erlang:element(4, State),
erlang:element(5, State),
up,
erlang:element(7, State)};
{{some, {ok, {key, K@2}}}, right} when (erlang:element(2, K@2) =:= {char,
<<"a"/utf8>>}) orelse (erlang:element(2, K@2) =:= left_arrow) ->
State;
{{some, {ok, {key, K@3}}}, _} when (erlang:element(2, K@3) =:= {char,
<<"a"/utf8>>}) orelse (erlang:element(2, K@3) =:= left_arrow) ->
{state,
erlang:element(2, State),
erlang:element(3, State),
erlang:element(4, State),
erlang:element(5, State),
left,
erlang:element(7, State)};
{{some, {ok, {key, K@4}}}, up} when (erlang:element(2, K@4) =:= {char,
<<"s"/utf8>>}) orelse (erlang:element(2, K@4) =:= down_arrow) ->
State;
{{some, {ok, {key, K@5}}}, _} when (erlang:element(2, K@5) =:= {char,
<<"s"/utf8>>}) orelse (erlang:element(2, K@5) =:= down_arrow) ->
{state,
erlang:element(2, State),
erlang:element(3, State),
erlang:element(4, State),
erlang:element(5, State),
down,
erlang:element(7, State)};
{{some, {ok, {key, K@6}}}, left} when (erlang:element(2, K@6) =:= {char,
<<"d"/utf8>>}) orelse (erlang:element(2, K@6) =:= right_arrow) ->
State;
{{some, {ok, {key, K@7}}}, _} when (erlang:element(2, K@7) =:= {char,
<<"d"/utf8>>}) orelse (erlang:element(2, K@7) =:= right_arrow) ->
{state,
erlang:element(2, State),
erlang:element(3, State),
erlang:element(4, State),
erlang:element(5, State),
right,
erlang:element(7, State)};
{{some, _}, _} ->
State;
{none, _} ->
State
end.
-file("src/examples/snake.gleam", 242).
?DOC(false).
-spec spawn_fruit(state()) -> state().
spawn_fruit(State) ->
F = gleam@int:random(erlang:element(4, State) * erlang:element(5, State)),
case gleam_stdlib:map_get(erlang:element(2, State), F) of
{ok, 1} ->
spawn_fruit(State);
{ok, 0} ->
Grid = gleam@dict:insert(erlang:element(2, State), F, 2),
{state,
Grid,
erlang:element(3, State),
erlang:element(4, State),
erlang:element(5, State),
erlang:element(6, State),
erlang:element(7, State)};
_ ->
erlang:error(#{gleam_error => panic,
message => <<"Unreachable"/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"examples/snake"/utf8>>,
function => <<"spawn_fruit"/utf8>>,
line => 253})
end.
-file("src/examples/snake.gleam", 257).
?DOC(false).
-spec remove_last_snake_block(state(), integer()) -> state().
remove_last_snake_block(State, New_head) ->
Snake = begin
_pipe = [New_head | erlang:element(3, State)],
lists:reverse(_pipe)
end,
{Last@1, Snake@1} = case Snake of
[Last | Rest] ->
{Last, Rest};
_ ->
erlang:error(#{gleam_error => panic,
message => <<"Unreachable"/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"examples/snake"/utf8>>,
function => <<"remove_last_snake_block"/utf8>>,
line => 264})
end,
Grid = gleam@dict:insert(erlang:element(2, State), Last@1, 0),
Grid@1 = gleam@dict:insert(Grid, New_head, 1),
Snake@2 = lists:reverse(Snake@1),
{state,
Grid@1,
Snake@2,
erlang:element(4, State),
erlang:element(5, State),
erlang:element(6, State),
erlang:element(7, State)}.
-file("src/examples/snake.gleam", 348).
?DOC(false).
-spec colorize_line(binary(), integer()) -> binary().
colorize_line(Str, Offset) ->
_pipe = gleam@string:to_graphemes(Str),
_pipe@1 = gleam@list:index_map(
_pipe,
fun(Ch, I) ->
Bg = case (I + Offset) rem 2 of
0 ->
{ansi_value, 254};
1 ->
{ansi_value, 188};
_ ->
erlang:error(#{gleam_error => panic,
message => <<"Unreachable"/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"examples/snake"/utf8>>,
function => <<"colorize_line"/utf8>>,
line => 355})
end,
case Ch of
<<"@"/utf8>> ->
etch@style:with_on(Ch, bright_green, Bg);
<<"$"/utf8>> ->
etch@style:with_on(Ch, red, Bg);
_ ->
etch@style:with_on(Ch, default, Bg)
end
end
),
gleam@string:join(_pipe@1, <<""/utf8>>).
-file("src/examples/snake.gleam", 342).
?DOC(false).
-spec colorize(list(binary())) -> list(etch@command:command()).
colorize(Strings) ->
gleam@list:index_map(
Strings,
fun(Str, I) -> {println, colorize_line(Str, I rem 2)} end
).
-file("src/examples/snake.gleam", 272).
?DOC(false).
-spec draw(state()) -> etch@stdout:queue().
draw(State) ->
L = maps:to_list(erlang:element(2, State)),
L@1 = gleam@list:sort(
L,
fun(X, Y) ->
gleam@int:compare(erlang:element(1, X), erlang:element(1, Y))
end
),
Q = {queue, [{move_to, 0, 0}]},
Strings = gleam@list:fold(
L@1,
{[], gleam@string_tree:new()},
fun(S, Cell) -> case Cell of
{Pos, 0} when (Pos rem erlang:element(5, State)) =:= (erlang:element(
5,
State
) - 1) ->
{[begin
_pipe = gleam@string_tree:append(
erlang:element(2, S),
<<" │"/utf8>>
),
unicode:characters_to_binary(_pipe)
end |
erlang:element(1, S)],
gleam@string_tree:new()};
{Pos@1, 1} when (Pos@1 rem erlang:element(5, State)) =:= (erlang:element(
5,
State
) - 1) ->
{[begin
_pipe@1 = gleam@string_tree:append(
erlang:element(2, S),
<<"@│"/utf8>>
),
unicode:characters_to_binary(_pipe@1)
end |
erlang:element(1, S)],
gleam@string_tree:new()};
{Pos@2, 2} when (Pos@2 rem erlang:element(5, State)) =:= (erlang:element(
5,
State
) - 1) ->
{[begin
_pipe@2 = gleam@string_tree:append(
erlang:element(2, S),
<<"$│"/utf8>>
),
unicode:characters_to_binary(_pipe@2)
end |
erlang:element(1, S)],
gleam@string_tree:new()};
{Pos@3, 0} when (Pos@3 rem erlang:element(5, State)) =:= 0 ->
{erlang:element(1, S),
gleam@string_tree:append(
erlang:element(2, S),
<<"│ "/utf8>>
)};
{Pos@4, 1} when (Pos@4 rem erlang:element(5, State)) =:= 0 ->
{erlang:element(1, S),
gleam@string_tree:append(
erlang:element(2, S),
<<"│@"/utf8>>
)};
{Pos@5, 2} when (Pos@5 rem erlang:element(5, State)) =:= 0 ->
{erlang:element(1, S),
gleam@string_tree:append(
erlang:element(2, S),
<<"│$"/utf8>>
)};
{_, 0} ->
{erlang:element(1, S),
gleam@string_tree:append(
erlang:element(2, S),
<<" "/utf8>>
)};
{_, 1} ->
{erlang:element(1, S),
gleam@string_tree:append(
erlang:element(2, S),
<<"@"/utf8>>
)};
{_, 2} ->
{erlang:element(1, S),
gleam@string_tree:append(
erlang:element(2, S),
<<"$"/utf8>>
)};
{_, _} ->
erlang:error(#{gleam_error => panic,
message => <<"Unreachable"/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"examples/snake"/utf8>>,
function => <<"draw"/utf8>>,
line => 319})
end end
),
Score_string = <<"Score: "/utf8,
(erlang:integer_to_binary(erlang:element(7, State)))/binary>>,
Score_string_len = string:length(Score_string),
Upper_border = <<<<<<"┌"/utf8, Score_string/binary>>/binary,
(gleam@string:repeat(
<<"─"/utf8>>,
erlang:element(5, State) - Score_string_len
))/binary>>/binary,
"┐"/utf8>>,
Lower_border = <<<<"└"/utf8,
(gleam@string:repeat(<<"─"/utf8>>, erlang:element(5, State)))/binary>>/binary,
"┘"/utf8>>,
Strings@1 = [Lower_border | erlang:element(1, Strings)],
Strings@2 = begin
_pipe@3 = lists:reverse(Strings@1),
gleam@list:prepend(_pipe@3, Upper_border)
end,
Q1 = colorize(Strings@2),
Q@1 = etch@stdout:queue(Q, Q1),
Q@2 = etch@stdout:queue(Q@1, [reset_style]),
etch@stdout:flush(Q@2).
-file("src/examples/snake.gleam", 381).
?DOC(false).
-spec print_centered_colored_block(state(), binary(), etch@style:color()) -> list(etch@command:command()).
print_centered_colored_block(State, S, C) ->
Len = string:length(S),
S@1 = <<<<"│"/utf8, S/binary>>/binary, "│"/utf8>>,
X = erlang:element(5, State),
Y = erlang:element(4, State) div 2,
X_offset = (Len div 2) - 1,
X@1 = (X div 2) - X_offset,
Upper_border = <<<<"┌"/utf8,
(gleam@string:repeat(<<"─"/utf8>>, Len))/binary>>/binary,
"┐"/utf8>>,
Lower_border = <<<<"└"/utf8,
(gleam@string:repeat(<<"─"/utf8>>, Len))/binary>>/binary,
"┘"/utf8>>,
[{set_foreground_color, C},
{move_to, X@1, Y - 1},
{print, Upper_border},
{move_to, X@1, Y},
{print, S@1},
{move_to, X@1, Y + 1},
{print, Lower_border},
reset_style].
-file("src/examples/snake.gleam", 367).
?DOC(false).
-spec lose(state()) -> nil.
lose(State) ->
etch@stdout:execute(
print_centered_colored_block(State, <<"You Lose"/utf8>>, red)
),
gleam_erlang_ffi:sleep(2000),
etch@stdout:execute([{clear, all}, leave_alternate_screen]),
erlang:halt(1).
-file("src/examples/snake.gleam", 374).
?DOC(false).
-spec win(state()) -> nil.
win(State) ->
etch@stdout:execute(
print_centered_colored_block(State, <<"You Win"/utf8>>, green)
),
gleam_erlang_ffi:sleep(2000),
etch@stdout:execute([{clear, all}, leave_alternate_screen]),
erlang:halt(0).
-file("src/examples/snake.gleam", 209).
?DOC(false).
-spec handle_new_head(state(), integer()) -> state().
handle_new_head(State, New_head) ->
case gleam_stdlib:map_get(erlang:element(2, State), New_head) of
{ok, 1} ->
lose(State),
State;
{ok, 2} ->
State@1 = {state,
erlang:element(2, State),
erlang:element(3, State),
erlang:element(4, State),
erlang:element(5, State),
erlang:element(6, State),
erlang:element(7, State) + 1},
_ = case (erlang:element(7, State@1) + 3) =:= (erlang:element(
4,
State@1
)
* erlang:element(5, State@1)) of
true ->
win(State@1);
false ->
nil
end,
Snake = [New_head | erlang:element(3, State@1)],
Grid = gleam@dict:insert(erlang:element(2, State@1), New_head, 1),
State@2 = {state,
Grid,
Snake,
erlang:element(4, State@1),
erlang:element(5, State@1),
erlang:element(6, State@1),
erlang:element(7, State@1)},
spawn_fruit(State@2);
{ok, 0} ->
remove_last_snake_block(State, New_head);
_ ->
erlang:error(#{gleam_error => panic,
message => <<"Unreachable"/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"examples/snake"/utf8>>,
function => <<"handle_new_head"/utf8>>,
line => 238})
end.
-file("src/examples/snake.gleam", 153).
?DOC(false).
-spec move_right(state()) -> state().
move_right(State) ->
Head@1 = case gleam@list:first(erlang:element(3, State)) of
{ok, Head} -> Head;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"examples/snake"/utf8>>,
function => <<"move_right"/utf8>>,
line => 154,
value => _assert_fail,
start => 4738,
'end' => 4783,
pattern_start => 4749,
pattern_end => 4757})
end,
New_head = case Head@1 of
N when (N rem erlang:element(5, State)) =:= (erlang:element(5, State) - 1) ->
lose(State),
0;
N@1 ->
N@1 + 1
end,
handle_new_head(State, New_head).
-file("src/examples/snake.gleam", 167).
?DOC(false).
-spec move_down(state()) -> state().
move_down(State) ->
Head@1 = case gleam@list:first(erlang:element(3, State)) of
{ok, Head} -> Head;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"examples/snake"/utf8>>,
function => <<"move_down"/utf8>>,
line => 168,
value => _assert_fail,
start => 5120,
'end' => 5165,
pattern_start => 5131,
pattern_end => 5139})
end,
New_head = case Head@1 + erlang:element(5, State) of
N when N > (erlang:element(5, State) * erlang:element(4, State)) ->
lose(State),
0;
N@1 ->
N@1
end,
handle_new_head(State, New_head).
-file("src/examples/snake.gleam", 181).
?DOC(false).
-spec move_left(state()) -> state().
move_left(State) ->
Head@1 = case gleam@list:first(erlang:element(3, State)) of
{ok, Head} -> Head;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"examples/snake"/utf8>>,
function => <<"move_left"/utf8>>,
line => 184,
value => _assert_fail,
start => 5630,
'end' => 5675,
pattern_start => 5641,
pattern_end => 5649})
end,
New_head = case Head@1 of
N when (N rem erlang:element(5, State)) =:= 0 ->
lose(State),
0;
N@1 ->
N@1 - 1
end,
handle_new_head(State, New_head).
-file("src/examples/snake.gleam", 195).
?DOC(false).
-spec move_up(state()) -> state().
move_up(State) ->
Head@1 = case gleam@list:first(erlang:element(3, State)) of
{ok, Head} -> Head;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"examples/snake"/utf8>>,
function => <<"move_up"/utf8>>,
line => 196,
value => _assert_fail,
start => 5869,
'end' => 5914,
pattern_start => 5880,
pattern_end => 5888})
end,
New_head = case Head@1 - erlang:element(5, State) of
N when N < 0 ->
lose(State),
0;
N@1 ->
N@1
end,
handle_new_head(State, New_head).
-file("src/examples/snake.gleam", 144).
?DOC(false).
-spec update_state(state()) -> state().
update_state(State) ->
case erlang:element(6, State) of
up ->
move_up(State);
down ->
move_down(State);
left ->
move_left(State);
right ->
move_right(State)
end.
-file("src/examples/snake.gleam", 97).
?DOC(false).
-spec loop(state()) -> any().
loop(State) ->
gleam_erlang_ffi:sleep(200),
State@1 = handle_input(State),
State@2 = update_state(State@1),
draw(State@2),
loop(State@2).
-file("src/examples/snake.gleam", 47).
?DOC(false).
-spec main() -> any().
main() ->
etch@stdout:execute(
[enter_raw,
enter_alternate_screen,
{clear, all},
hide_cursor,
disable_line_wrap]
),
{Columns, Rows} = terminal_ffi:window_size(),
{Columns@1, Rows@1} = {Columns - 2, Rows - 2},
Grid = make_grid(Columns@1, Rows@1),
Snake_center = case gleam@int:is_even(Rows@1) of
true ->
((Rows@1 * Columns@1) div 2) + (Columns@1 div 2);
false ->
(Rows@1 * Columns@1) div 2
end,
State = {state,
Grid,
[Snake_center, Snake_center - 1, Snake_center - 2],
Rows@1,
Columns@1,
right,
0},
State@1 = spawn_fruit(State),
etch@event:init_event_server(),
loop(State@1).