diff options
author | Elizabeth (Lizzy) Hunt <elizabeth.hunt@simponic.xyz> | 2023-05-29 16:28:27 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-05-29 16:28:27 -0700 |
commit | eec32aa38a8762eccc8575a37a628bd5ae2cc1d0 (patch) | |
tree | 27f656780f5d25325c9ac0ec3db3557d774bf414 /lib/chessh/ssh | |
parent | 8a5a2f358cb1f63a255b2daf6908536583986448 (diff) | |
download | chessh-eec32aa38a8762eccc8575a37a628bd5ae2cc1d0.tar.gz chessh-eec32aa38a8762eccc8575a37a628bd5ae2cc1d0.zip |
Bots (#23)
* squash all the things for bots
* fix warnings
* change colors a bit and README updates
* fix frontend warnings
Diffstat (limited to 'lib/chessh/ssh')
-rw-r--r-- | lib/chessh/ssh/client/client.ex | 4 | ||||
-rw-r--r-- | lib/chessh/ssh/client/game/game.ex | 87 | ||||
-rw-r--r-- | lib/chessh/ssh/client/game/renderer.ex | 92 | ||||
-rw-r--r-- | lib/chessh/ssh/client/menus/create_game.ex | 42 | ||||
-rw-r--r-- | lib/chessh/ssh/client/menus/main_menu.ex | 16 | ||||
-rw-r--r-- | lib/chessh/ssh/client/menus/select_bot.ex | 119 | ||||
-rw-r--r-- | lib/chessh/ssh/client/menus/select_current_game.ex | 9 | ||||
-rw-r--r-- | lib/chessh/ssh/client/menus/select_joinable_game.ex | 13 | ||||
-rw-r--r-- | lib/chessh/ssh/client/menus/select_paginate_poller.ex | 83 | ||||
-rw-r--r-- | lib/chessh/ssh/client/menus/select_previous_game.ex | 9 | ||||
-rw-r--r-- | lib/chessh/ssh/client/menus/selector.ex (renamed from lib/chessh/ssh/client/menus/game_selector.ex) | 3 |
11 files changed, 307 insertions, 170 deletions
diff --git a/lib/chessh/ssh/client/client.ex b/lib/chessh/ssh/client/client.ex index 882a90e..5a0ea1e 100644 --- a/lib/chessh/ssh/client/client.ex +++ b/lib/chessh/ssh/client/client.ex @@ -156,8 +156,8 @@ defmodule Chessh.SSH.Client do # C-b <<2>> -> :menu # Escape - "\e" -> :menu - # VIM keys, per request + "\e" -> :escape + # VIM keys "k" -> :up "j" -> :down "h" -> :left diff --git a/lib/chessh/ssh/client/game/game.ex b/lib/chessh/ssh/client/game/game.ex index 4fb28f3..738832e 100644 --- a/lib/chessh/ssh/client/game/game.ex +++ b/lib/chessh/ssh/client/game/game.ex @@ -1,10 +1,8 @@ defmodule Chessh.SSH.Client.Game do require Logger - alias Chessh.{Game, Utils, Repo} + alias Chessh.{Game, Utils, Repo, Bot} alias Chessh.SSH.Client.Game.Renderer - @default_fen "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1" - defmodule State do defstruct cursor: %{x: 7, y: 7}, highlighted: %{}, @@ -69,27 +67,14 @@ defmodule Chessh.SSH.Client.Game do case Hammer.check_rate_inc( :redis, - "player-#{state.player_session.id}-create-game-rate", + "player-#{state.player_session.player_id}-create-game-rate", create_game_ms, create_game_rate, 1 ) do {:allow, _count} -> - # Starting a new game - {:ok, %Game{id: game_id} = game} = - Game.changeset( - %Game{}, - Map.merge( - if(color == :light, - do: %{light_player_id: player_session.player_id}, - else: %{dark_player_id: player_session.player_id} - ), - %{ - fen: @default_fen - } - ) - ) - |> Repo.insert() + game = Game.new_game(color, player_session.player_id) |> Repo.insert!() + %Game{id: game_id} = game GenServer.cast( :discord_notifier, @@ -129,20 +114,23 @@ defmodule Chessh.SSH.Client.Game do id: game_id, fen: fen, dark_player_id: dark_player_id, - light_player_id: light_player_id + light_player_id: light_player_id, + bot_id: bot_id } = game } = state | _ ]) do maybe_changeset = - case color do - :light -> - if !light_player_id, - do: Game.changeset(game, %{light_player_id: player_session.player_id}) - - :dark -> - if !dark_player_id, - do: Game.changeset(game, %{dark_player_id: player_session.player_id}) + if !bot_id do + case(color) do + :light -> + if !light_player_id, + do: Game.changeset(game, %{light_player_id: player_session.player_id}) + + :dark -> + if !dark_player_id, + do: Game.changeset(game, %{dark_player_id: player_session.player_id}) + end end {status, maybe_joined_game} = @@ -164,7 +152,7 @@ defmodule Chessh.SSH.Client.Game do end binbo_pid = initialize_game(game_id, fen) - game = Repo.get(Game, game_id) |> Repo.preload([:light_player, :dark_player]) + game = Repo.get(Game, game_id) |> Repo.preload([:light_player, :dark_player, :bot]) player_color = if(game.light_player_id == player_session.player_id, do: :light, else: :dark) @@ -206,7 +194,7 @@ defmodule Chessh.SSH.Client.Game do } end).(%State{ state - | game: Repo.get(Game, game_id) |> Repo.preload([:light_player, :dark_player]) + | game: Repo.get(Game, game_id) |> Repo.preload([:light_player, :dark_player, :bot]) }) send(client_pid, {:send_to_ssh, Renderer.render_board_state(new_state)}) @@ -218,7 +206,7 @@ defmodule Chessh.SSH.Client.Game do :player_joined, %State{client_pid: client_pid, game: %Game{id: game_id}} = state ) do - game = Repo.get(Game, game_id) |> Repo.preload([:light_player, :dark_player]) + game = Repo.get(Game, game_id) |> Repo.preload([:light_player, :dark_player, :bot]) new_state = %State{state | game: game} send(client_pid, {:send_to_ssh, Renderer.render_board_state(new_state)}) {:noreply, new_state} @@ -365,7 +353,7 @@ defmodule Chessh.SSH.Client.Game do from, to, %State{ - game: %Game{game_moves: game_moves, id: game_id, turn: turn}, + game: %Game{id: game_id, turn: turn}, binbo_pid: binbo_pid, flipped: flipped, color: turn @@ -391,22 +379,15 @@ defmodule Chessh.SSH.Client.Game do {:ok, status} -> {:ok, fen} = :binbo.get_fen(binbo_pid) - {:ok, %Game{status: after_move_status}} = + {:ok, %Game{status: after_move_status} = game} = game - |> Game.changeset( - Map.merge( - %{ - fen: fen, - moves: game.moves + 1, - turn: if(game.turn == :dark, do: :light, else: :dark), - last_move: attempted_move, - game_moves: if(game_moves, do: game_moves <> " ", else: "") <> attempted_move - }, - changeset_from_status(status) - ) - ) + |> Game.update_with_status(attempted_move, fen, status) |> Repo.update() + if !is_nil(game.bot) do + spawn(fn -> Bot.send_update(Repo.get(Game, game.id) |> Repo.preload([:bot])) end) + end + :syn.publish(:games, {:game, game_id}, {:new_move, attempted_move}) if after_move_status == :continue do @@ -433,22 +414,6 @@ defmodule Chessh.SSH.Client.Game do nil end - defp changeset_from_status(game_status) do - case game_status do - :continue -> - %{} - - {:draw, _} -> - %{status: :draw} - - {:checkmate, :white_wins} -> - %{status: :winner, winner: :light} - - {:checkmate, :black_wins} -> - %{status: :winner, winner: :dark} - end - end - defp make_highlight_map( %State{ game: %Game{last_move: last_move, turn: turn}, diff --git a/lib/chessh/ssh/client/game/renderer.ex b/lib/chessh/ssh/client/game/renderer.ex index b9071a9..ecd1803 100644 --- a/lib/chessh/ssh/client/game/renderer.ex +++ b/lib/chessh/ssh/client/game/renderer.ex @@ -2,6 +2,7 @@ defmodule Chessh.SSH.Client.Game.Renderer do alias IO.ANSI alias Chessh.{Utils, Player} alias Chessh.SSH.Client.Game + require Logger @chess_board_height 8 @chess_board_width 8 @@ -9,10 +10,11 @@ defmodule Chessh.SSH.Client.Game.Renderer do @tile_width 7 @tile_height 4 - @previous_move_background ANSI.light_magenta_background() - @from_select_background ANSI.light_green_background() - @to_select_background ANSI.light_yellow_background() - @in_check_color ANSI.yellow_background() + @previous_move_background ANSI.color_background(208) + @from_select_background ANSI.color_background(105) + + @to_select_background ANSI.color_background(177) + @in_check_color ANSI.color_background(197) @dark_piece_color ANSI.red() @light_piece_color ANSI.light_cyan() @@ -42,29 +44,17 @@ defmodule Chessh.SSH.Client.Game.Renderer do %Game.State{ game: %Chessh.Game{ - light_player: light_player - } = game - } = state - ) - when is_nil(light_player) do - render_board_state(%Game.State{ - state - | game: %Chessh.Game{game | light_player: %Player{username: "(no opponent)"}} - }) - end - - def render_board_state( - %Game.State{ - game: - %Chessh.Game{ + light_player: light_player, dark_player: dark_player } = game } = state ) - when is_nil(dark_player) do + when is_nil(light_player) or is_nil(dark_player) do + {light_player, dark_player} = get_players(game) + render_board_state(%Game.State{ state - | game: %Chessh.Game{game | dark_player: %Player{username: "(no opponent)"}} + | game: %Chessh.Game{game | light_player: light_player, dark_player: dark_player} }) end @@ -73,9 +63,12 @@ defmodule Chessh.SSH.Client.Game.Renderer do flipped: flipped, game: %Chessh.Game{ - fen: fen + fen: fen, + light_player: light_player, + dark_player: dark_player } = game - }) do + }) + when not is_nil(light_player) and not is_nil(dark_player) do rendered = [ ANSI.clear_line(), make_status_line(game, true) @@ -98,29 +91,19 @@ defmodule Chessh.SSH.Client.Game.Renderer do def make_status_line( %Chessh.Game{ - light_player: light_player - } = game, - fancy - ) - when is_nil(light_player), - do: - make_status_line( - %Chessh.Game{game | light_player: %Player{username: "(no opponent)"}}, - fancy - ) - - def make_status_line( - %Chessh.Game{ + light_player: light_player, dark_player: dark_player } = game, fancy ) - when is_nil(dark_player), - do: - make_status_line( - %Chessh.Game{game | dark_player: %Player{username: "(no opponent)"}}, - fancy - ) + when is_nil(light_player) or is_nil(dark_player) do + {light_player, dark_player} = get_players(game) + + make_status_line( + %Chessh.Game{game | light_player: light_player, dark_player: dark_player}, + fancy + ) + end def make_status_line( %Chessh.Game{ @@ -143,12 +126,12 @@ defmodule Chessh.SSH.Client.Game.Renderer do "Game #{game_id} - ", if(fancy, do: ANSI.format_fragment([@light_piece_color, light_player]), - else: "#{light_player} (L)" + else: "♔ #{light_player}" ), "#{if fancy, do: ANSI.default_color(), else: ""} --vs-- ", if(fancy, do: ANSI.format_fragment([@dark_piece_color, dark_player]), - else: "#{dark_player} (D)" + else: "♚ #{dark_player}" ), if(fancy, do: ANSI.default_color(), else: ""), case status do @@ -373,4 +356,25 @@ defmodule Chessh.SSH.Client.Game.Renderer do Map.merge(acc, pieces_map_for_this_row) end) end + + defp get_players( + %Chessh.Game{light_player: light_player, dark_player: dark_player, bot: bot} = game + ) do + case {is_nil(light_player), is_nil(dark_player), is_nil(bot)} do + {false, true, false} -> + {game.light_player, %Player{username: bot.name}} + + {true, false, false} -> + {%Player{username: bot.name}, game.dark_player} + + {true, false, true} -> + {%Player{username: "(no opponent)"}, game.dark_player} + + {false, true, true} -> + {game.light_player, %Player{username: "(no opponent)"}} + + {false, false, true} -> + {game.light_player, game.dark_player} + end + end end diff --git a/lib/chessh/ssh/client/menus/create_game.ex b/lib/chessh/ssh/client/menus/create_game.ex new file mode 100644 index 0000000..99d2c0e --- /dev/null +++ b/lib/chessh/ssh/client/menus/create_game.ex @@ -0,0 +1,42 @@ +defmodule Chessh.SSH.Client.CreateGameMenu do + alias IO.ANSI + + alias Chessh.PlayerSession + alias Chessh.SSH.Client.Game + + require Logger + + use Chessh.SSH.Client.SelectPaginatePoller + + def dynamic_options(), do: false + def tick_delay_ms(), do: 1000 + def max_displayed_options(), do: 4 + def title(), do: ["-- Create A New Game --"] + + def initial_options(%State{player_session: %PlayerSession{} = player_session}) do + [ + {"😀 vs 😀 | ⬜ White", {Game, %Game.State{player_session: player_session, color: :light}}}, + {"😀 vs 😀 | ⬛ Black", {Game, %Game.State{player_session: player_session, color: :dark}}}, + {"😀 vs 🤖 | ⬜ White", + {Chessh.SSH.Client.SelectBot, + %Chessh.SSH.Client.SelectPaginatePoller.State{ + player_session: player_session, + extra_info: %{ + color: :light + } + }}}, + {"🤖 vs 😀 | ⬛ Black", + {Chessh.SSH.Client.SelectBot, + %Chessh.SSH.Client.SelectPaginatePoller.State{ + player_session: player_session, + extra_info: %{ + color: :dark + } + }}} + ] + end + + def make_process_tuple(selected, _state) do + selected + end +end diff --git a/lib/chessh/ssh/client/menus/main_menu.ex b/lib/chessh/ssh/client/menus/main_menu.ex index ee4b976..7b83b76 100644 --- a/lib/chessh/ssh/client/menus/main_menu.ex +++ b/lib/chessh/ssh/client/menus/main_menu.ex @@ -1,6 +1,5 @@ defmodule Chessh.SSH.Client.MainMenu do alias IO.ANSI - alias Chessh.PlayerSession require Logger @@ -22,9 +21,12 @@ defmodule Chessh.SSH.Client.MainMenu do def max_box_cols(), do: @logo_cols def title(), do: @logo ++ ["- Connected on: #{System.get_env("NODE_ID")}"] - def initial_options(%State{player_session: %PlayerSession{} = player_session}) do + def initial_options(%State{player_session: player_session}) do [ - {"My Current Games", + {"Create Game", + {Chessh.SSH.Client.CreateGameMenu, + %Chessh.SSH.Client.SelectPaginatePoller.State{player_session: player_session}}}, + {"Current Games", {Chessh.SSH.Client.SelectCurrentGame, %Chessh.SSH.Client.SelectPaginatePoller.State{player_session: player_session}}}, {"Joinable Games (lobby)", @@ -32,13 +34,7 @@ defmodule Chessh.SSH.Client.MainMenu do %Chessh.SSH.Client.SelectPaginatePoller.State{player_session: player_session}}}, {"Previous Games", {Chessh.SSH.Client.SelectPreviousGame, - %Chessh.SSH.Client.SelectPaginatePoller.State{player_session: player_session}}}, - {"Start A Game (Light)", - {Chessh.SSH.Client.Game, - %Chessh.SSH.Client.Game.State{player_session: player_session, color: :light}}}, - {"Start A Game (Dark)", - {Chessh.SSH.Client.Game, - %Chessh.SSH.Client.Game.State{player_session: player_session, color: :dark}}} + %Chessh.SSH.Client.SelectPaginatePoller.State{player_session: player_session}}} ] end diff --git a/lib/chessh/ssh/client/menus/select_bot.ex b/lib/chessh/ssh/client/menus/select_bot.ex new file mode 100644 index 0000000..86fc7cd --- /dev/null +++ b/lib/chessh/ssh/client/menus/select_bot.ex @@ -0,0 +1,119 @@ +defmodule Chessh.SSH.Client.SelectBot do + alias Chessh.{Utils, Bot, Repo, Game} + alias Chessh.SSH.Client.Selector + import Ecto.Query + require Logger + + use Chessh.SSH.Client.SelectPaginatePoller + + def refresh_options_ms(), do: 4000 + def max_displayed_options(), do: 5 + def title(), do: ["-- Select Bot To Play Against --"] + def dynamic_options(), do: true + + def get_bots(player_id, current_id \\ nil, direction \\ :desc) do + Selector.paginate_ish_query( + Bot + |> where([b], b.player_id == ^player_id or b.public == true) + |> limit(^max_displayed_options()), + current_id, + direction + ) + end + + def format_bot_tuple(%Bot{id: id, name: name}), do: {name, id} + + def next_page_options(%State{ + options: options, + player_session: %PlayerSession{ + player_id: player_id + } + }) do + {_label, previous_last_bot_id} = List.last(options) + next_bots = get_bots(player_id, previous_last_bot_id, :desc) + + if length(next_bots) > 0, + do: + next_bots + |> Enum.map(&format_bot_tuple/1), + else: options + end + + def previous_page_options(%State{ + options: options, + player_session: %PlayerSession{player_id: player_id} + }) do + {_label, previous_first_bot_id} = List.first(options) + + previous_bots = get_bots(player_id, previous_first_bot_id, :asc) + + if length(previous_bots) > 0, + do: + previous_bots + |> Enum.map(&format_bot_tuple/1), + else: options + end + + def initial_options(%State{ + player_session: %PlayerSession{player_id: player_id} + }) do + get_bots(player_id) + |> Enum.map(&format_bot_tuple/1) + end + + def refresh_options(%State{ + options: options, + player_session: %PlayerSession{player_id: player_id} + }) do + previous_last_bot_id = + case List.last(options) do + {_name, id} -> id + _ -> 1 + end + + current_screen_games = get_bots(player_id, previous_last_bot_id - 1, :asc) + + if !is_nil(current_screen_games) && length(current_screen_games), + do: + current_screen_games + |> Enum.map(&format_bot_tuple/1), + else: options + end + + def make_process_tuple(selected_id, %State{ + player_session: player_session, + extra_info: %{color: color} + }) do + [create_game_ms, create_game_rate] = + Application.get_env(:chessh, RateLimits) + |> Keyword.take([:create_game_ms, :create_game_rate]) + |> Keyword.values() + + case Hammer.check_rate_inc( + :redis, + "player-#{player_session.player_id}-create-game-rate", + create_game_ms, + create_game_rate, + 1 + ) do + {:allow, _count} -> + {:ok, game} = + Game.changeset( + Game.new_game(color, player_session.player_id), + %{ + bot_id: selected_id + } + ) + |> Repo.insert() + + spawn(fn -> Bot.send_update(game |> Repo.preload([:bot])) end) + + {Chessh.SSH.Client.Game, + %Chessh.SSH.Client.Game.State{player_session: player_session, color: color, game: game}} + + {:deny, _limit} -> + {Chessh.SSH.Client.MainMenu, + %Chessh.SSH.Client.SelectPaginatePoller.State{player_session: player_session}} + end + end +end diff --git a/lib/chessh/ssh/client/menus/select_current_game.ex b/lib/chessh/ssh/client/menus/select_current_game.ex index 3c47b15..7c49a30 100644 --- a/lib/chessh/ssh/client/menus/select_current_game.ex +++ b/lib/chessh/ssh/client/menus/select_current_game.ex @@ -1,6 +1,6 @@ defmodule Chessh.SSH.Client.SelectCurrentGame do alias Chessh.{Utils, Repo, Game, PlayerSession} - alias Chessh.SSH.Client.GameSelector + alias Chessh.SSH.Client.Selector import Ecto.Query require Logger @@ -12,7 +12,7 @@ defmodule Chessh.SSH.Client.SelectCurrentGame do def dynamic_options(), do: true def get_player_sorted_current_games_with_id(player_id, current_id \\ nil, direction \\ :desc) do - GameSelector.paginate_ish_query( + Selector.paginate_ish_query( Game |> where([g], g.status == :continue) |> where([g], g.light_player_id == ^player_id or g.dark_player_id == ^player_id) @@ -20,6 +20,7 @@ defmodule Chessh.SSH.Client.SelectCurrentGame do current_id, direction ) + |> Repo.preload([:light_player, :dark_player, :bot]) end def format_game_selection_tuple(%Game{id: game_id} = game) do @@ -67,7 +68,7 @@ defmodule Chessh.SSH.Client.SelectCurrentGame do order_by: [desc: g.id] ) |> Repo.all() - |> Repo.preload([:light_player, :dark_player]) + |> Repo.preload([:light_player, :dark_player, :bot]) |> Enum.map(&format_game_selection_tuple/1) end @@ -78,7 +79,7 @@ defmodule Chessh.SSH.Client.SelectCurrentGame do previous_last_game_id = case List.last(options) do {_label, id} -> id - _ -> 0 + _ -> 1 end current_screen_games = diff --git a/lib/chessh/ssh/client/menus/select_joinable_game.ex b/lib/chessh/ssh/client/menus/select_joinable_game.ex index f2b7b1f..b0d0cbe 100644 --- a/lib/chessh/ssh/client/menus/select_joinable_game.ex +++ b/lib/chessh/ssh/client/menus/select_joinable_game.ex @@ -1,7 +1,8 @@ defmodule Chessh.SSH.Client.SelectJoinableGame do alias Chessh.{Utils, Repo, Game, PlayerSession} - alias Chessh.SSH.Client.GameSelector + alias Chessh.SSH.Client.Selector import Ecto.Query + require Logger use Chessh.SSH.Client.SelectPaginatePoller @@ -12,18 +13,20 @@ defmodule Chessh.SSH.Client.SelectJoinableGame do def dynamic_options(), do: true def get_player_joinable_games_with_id(player_id, current_id \\ nil, direction \\ :desc) do - GameSelector.paginate_ish_query( + Selector.paginate_ish_query( Game |> where([g], g.status == :continue) |> where( [g], (is_nil(g.dark_player_id) or is_nil(g.light_player_id)) and - (g.dark_player_id != ^player_id or g.light_player_id != ^player_id) + (g.dark_player_id != ^player_id or g.light_player_id != ^player_id) and + is_nil(g.bot_id) ) |> limit(^max_displayed_options()), current_id, direction ) + |> Repo.preload([:light_player, :dark_player, :bot]) end def format_game_selection_tuple(%Game{id: game_id} = game) do @@ -60,6 +63,8 @@ defmodule Chessh.SSH.Client.SelectJoinableGame do end def initial_options(%State{player_session: %PlayerSession{player_id: player_id}}) do + Logger.info(player_id) + get_player_joinable_games_with_id(player_id) |> Enum.map(&format_game_selection_tuple/1) end @@ -71,7 +76,7 @@ defmodule Chessh.SSH.Client.SelectJoinableGame do previous_last_game_id = case List.last(options) do {_label, id} -> id - _ -> 0 + _ -> 1 end current_screen_games = diff --git a/lib/chessh/ssh/client/menus/select_paginate_poller.ex b/lib/chessh/ssh/client/menus/select_paginate_poller.ex index adca697..23808b5 100644 --- a/lib/chessh/ssh/client/menus/select_paginate_poller.ex +++ b/lib/chessh/ssh/client/menus/select_paginate_poller.ex @@ -26,7 +26,8 @@ defmodule Chessh.SSH.Client.SelectPaginatePoller do player_session: nil, options: [], tick: 0, - cursor: nil + cursor: nil, + extra_info: %{} end defmacro __using__(_) do @@ -127,51 +128,55 @@ defmodule Chessh.SSH.Client.SelectPaginatePoller do max_item = min(length(options), max_displayed_options()) new_state = - if(max_item > 0, - do: - case action do - :up -> - %State{ - state - | selected_option_idx: Utils.wrap_around(selected_option_idx, -1, max_item), - tick: 0 - } - - :down -> - %State{ - state - | selected_option_idx: Utils.wrap_around(selected_option_idx, 1, max_item), - tick: 0 - } - - :left -> - if dynamic_options(), - do: %State{ + if max_item > 0 do + if action == :return do + {_, selected} = Enum.at(options, selected_option_idx) + {module, state} = make_process_tuple(selected, state) + send(client_pid, {:set_screen_process, module, state}) + state + else + if(max_item > 1) do + case action do + :up -> + %State{ state - | options: previous_page_options(state), - selected_option_idx: 0, + | selected_option_idx: Utils.wrap_around(selected_option_idx, -1, max_item), tick: 0 } - :right -> - if dynamic_options(), - do: %State{ + :down -> + %State{ state - | options: next_page_options(state), - selected_option_idx: 0, + | selected_option_idx: Utils.wrap_around(selected_option_idx, 1, max_item), tick: 0 } - :return -> - {_, selected} = Enum.at(options, selected_option_idx) - {module, state} = make_process_tuple(selected, state) - send(client_pid, {:set_screen_process, module, state}) - state - - _ -> - nil + :left -> + if dynamic_options(), + do: %State{ + state + | options: previous_page_options(state), + selected_option_idx: 0, + tick: 0 + } + + :right -> + if dynamic_options(), + do: %State{ + state + | options: next_page_options(state), + selected_option_idx: 0, + tick: 0 + } + + _ -> + state + end + else + state end - ) || state + end + end if !(action == :return) do render(width, height, new_state) @@ -229,7 +234,7 @@ defmodule Chessh.SSH.Client.SelectPaginatePoller do if i == selected_option_idx do ANSI.format_fragment( - [:light_cyan, :bright, "> #{line} <", :reset], + [:light_cyan, :bright, "♜ #{line} ♜", :reset], true ) else @@ -238,7 +243,7 @@ defmodule Chessh.SSH.Client.SelectPaginatePoller do end ) else - ["Looks like there's nothing here.", "Use Ctrl+b to go back."] + ["Looks like there's nothing here.", "Use Ctrl+b return to the menu."] end end diff --git a/lib/chessh/ssh/client/menus/select_previous_game.ex b/lib/chessh/ssh/client/menus/select_previous_game.ex index 5f55c3d..c348268 100644 --- a/lib/chessh/ssh/client/menus/select_previous_game.ex +++ b/lib/chessh/ssh/client/menus/select_previous_game.ex @@ -1,6 +1,6 @@ defmodule Chessh.SSH.Client.SelectPreviousGame do alias Chessh.{Utils, Repo, Game, PlayerSession} - alias Chessh.SSH.Client.GameSelector + alias Chessh.SSH.Client.Selector import Ecto.Query require Logger @@ -12,7 +12,7 @@ defmodule Chessh.SSH.Client.SelectPreviousGame do def dynamic_options(), do: true def get_player_sorted_current_games_with_id(player_id, current_id \\ nil, direction \\ :desc) do - GameSelector.paginate_ish_query( + Selector.paginate_ish_query( Game |> where([g], g.status != :continue) |> where([g], g.light_player_id == ^player_id or g.dark_player_id == ^player_id) @@ -20,6 +20,7 @@ defmodule Chessh.SSH.Client.SelectPreviousGame do current_id, direction ) + |> Repo.preload([:light_player, :dark_player, :bot]) end def format_game_selection_tuple(%Game{id: game_id} = game) do @@ -67,7 +68,7 @@ defmodule Chessh.SSH.Client.SelectPreviousGame do order_by: [desc: g.id] ) |> Repo.all() - |> Repo.preload([:light_player, :dark_player]) + |> Repo.preload([:light_player, :dark_player, :bot]) |> Enum.map(&format_game_selection_tuple/1) end @@ -78,7 +79,7 @@ defmodule Chessh.SSH.Client.SelectPreviousGame do previous_last_game_id = case List.last(options) do {_label, id} -> id - _ -> 0 + _ -> 1 end current_screen_games = diff --git a/lib/chessh/ssh/client/menus/game_selector.ex b/lib/chessh/ssh/client/menus/selector.ex index 7792082..225c41f 100644 --- a/lib/chessh/ssh/client/menus/game_selector.ex +++ b/lib/chessh/ssh/client/menus/selector.ex @@ -1,4 +1,4 @@ -defmodule Chessh.SSH.Client.GameSelector do +defmodule Chessh.SSH.Client.Selector do import Ecto.Query alias Chessh.Repo @@ -17,7 +17,6 @@ defmodule Chessh.SSH.Client.GameSelector do sorted_query end |> Repo.all() - |> Repo.preload([:light_player, :dark_player]) if direction == :desc, do: results, else: Enum.reverse(results) end |