-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 => <>, 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 => <>, 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 => <>, 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 => <>, 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 => <>, 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 => <>, 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 => <>, 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 => <>, 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 => <>, 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).