From aa5aad7715ada53e598f2923f01abca3fcdc2d96 Mon Sep 17 00:00:00 2001 From: Simponic Date: Wed, 8 Mar 2023 00:24:30 -0700 Subject: [PATCH] store move history --- lib/chessh/schema/game.ex | 5 +- lib/chessh/ssh/client/game/game.ex | 5 +- lib/chessh/ssh/client/menus/main_menu.ex | 17 +-- .../ssh/client/menus/select_previous_game.ex | 105 ++++++++++++++++++ .../20230304031125_add_move_history.exs | 9 ++ 5 files changed, 131 insertions(+), 10 deletions(-) create mode 100644 lib/chessh/ssh/client/menus/select_previous_game.ex create mode 100644 priv/repo/migrations/20230304031125_add_move_history.exs diff --git a/lib/chessh/schema/game.ex b/lib/chessh/schema/game.ex index 55b9ea4..868fec8 100644 --- a/lib/chessh/schema/game.ex +++ b/lib/chessh/schema/game.ex @@ -12,6 +12,8 @@ defmodule Chessh.Game do field(:winner, Ecto.Enum, values: [:light, :dark, :none], default: :none) field(:status, Ecto.Enum, values: [:continue, :draw, :winner], default: :continue) + field(:game_moves, :string) + belongs_to(:light_player, Player, foreign_key: :light_player_id) belongs_to(:dark_player, Player, foreign_key: :dark_player_id) @@ -31,7 +33,8 @@ defmodule Chessh.Game do :last_move, :light_player_id, :dark_player_id, - :discord_thread_id + :discord_thread_id, + :game_moves ]) end end diff --git a/lib/chessh/ssh/client/game/game.ex b/lib/chessh/ssh/client/game/game.ex index da2bd99..83ae765 100644 --- a/lib/chessh/ssh/client/game/game.ex +++ b/lib/chessh/ssh/client/game/game.ex @@ -370,7 +370,7 @@ defmodule Chessh.SSH.Client.Game do from, to, %State{ - game: %Game{id: game_id, turn: turn}, + game: %Game{game_moves: game_moves, id: game_id, turn: turn}, binbo_pid: binbo_pid, flipped: flipped, color: turn @@ -404,7 +404,8 @@ defmodule Chessh.SSH.Client.Game do fen: fen, moves: game.moves + 1, turn: if(game.turn == :dark, do: :light, else: :dark), - last_move: attempted_move + last_move: attempted_move, + game_moves: if(game_moves, do: game_moves <> " ", else: "") <> attempted_move }, changeset_from_status(status) ) diff --git a/lib/chessh/ssh/client/menus/main_menu.ex b/lib/chessh/ssh/client/menus/main_menu.ex index 09aea14..397b1b7 100644 --- a/lib/chessh/ssh/client/menus/main_menu.ex +++ b/lib/chessh/ssh/client/menus/main_menu.ex @@ -4,13 +4,13 @@ defmodule Chessh.SSH.Client.MainMenu do require Logger - @logo " Simponic's - dP MP\"\"\"\"\"\"`MM MP\"\"\"\"\"\"`MM M\"\"MMMMM\"\"MM - 88 M mmmmm..M M mmmmm..M M MMMMM MM -.d8888b. 88d888b. .d8888b. M. `YM M. `YM M `M -88' `\"\" 88' `88 88ooood8 MMMMMMM. M MMMMMMM. M M MMMMM MM -88. ... 88 88 88. ... M. .MMM' M M. .MMM' M M MMMMM MM -`88888P' dP dP `88888P' Mb. .dM Mb. .dM M MMMMM MM + @logo " Simponic's + dP MP\"\"\"\"\"\"`MM MP\"\"\"\"\"\"`MM M\"\"MMMMM\"\"MM + 88 M mmmmm..M M mmmmm..M M MMMMM MM +.d8888b. 88d888b. .d8888b. M. `YM M. `YM M `M +88' `\"\" 88' `88 88ooood8 MMMMMMM. M MMMMMMM. M M MMMMM MM +88. ... 88 88 88. ... M. .MMM' M M. .MMM' M M MMMMM MM +`88888P' dP dP `88888P' Mb. .dM Mb. .dM M MMMMM MM MMMMMMMMMMM MMMMMMMMMMM MMMMMMMMMMMM" |> String.split("\n") @logo_cols @logo |> Enum.map(&String.length/1) |> Enum.max() @@ -33,6 +33,9 @@ defmodule Chessh.SSH.Client.MainMenu do {"Current Games", {Chessh.SSH.Client.SelectCurrentGame, %Chessh.SSH.Client.SelectPaginatePoller.State{player_session: player_session}}}, + {"Previous Games", + {Chessh.SSH.Client.SelectPreviousGame, + %Chessh.SSH.Client.SelectPaginatePoller.State{player_session: player_session}}}, {"Joinable Games (lobby)", {Chessh.SSH.Client.SelectJoinableGame, %Chessh.SSH.Client.SelectPaginatePoller.State{player_session: player_session}}} diff --git a/lib/chessh/ssh/client/menus/select_previous_game.ex b/lib/chessh/ssh/client/menus/select_previous_game.ex new file mode 100644 index 0000000..7b02042 --- /dev/null +++ b/lib/chessh/ssh/client/menus/select_previous_game.ex @@ -0,0 +1,105 @@ +defmodule Chessh.SSH.Client.SelectPreviousGame do + alias Chessh.{Utils, Repo, Game, PlayerSession} + alias Chessh.SSH.Client.GameSelector + 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: ["-- Previous Games --"] + 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( + Game + |> where([g], g.status != :continue) + |> where([g], g.light_player_id == ^player_id or g.dark_player_id == ^player_id) + |> limit(^max_displayed_options()), + current_id, + direction + ) + end + + def format_game_selection_tuple(%Game{id: game_id} = game) do + {Chessh.SSH.Client.Game.Renderer.make_status_line(game, false), game_id} + end + + def next_page_options(%State{ + options: options, + player_session: %PlayerSession{player_id: player_id} + }) do + {_label, previous_last_game_id} = List.last(options) + next_games = get_player_sorted_current_games_with_id(player_id, previous_last_game_id, :desc) + + if length(next_games) > 0, + do: + next_games + |> Enum.map(&format_game_selection_tuple/1), + else: options + end + + def previous_page_options(%State{ + options: options, + player_session: %PlayerSession{player_id: player_id} + }) do + {_label, previous_first_game_id} = List.first(options) + + previous_games = + get_player_sorted_current_games_with_id(player_id, previous_first_game_id, :asc) + + if length(previous_games) > 0, + do: + previous_games + |> Enum.map(&format_game_selection_tuple/1), + else: options + end + + def initial_options(%State{player_session: %PlayerSession{player_id: player_id}}) do + get_player_sorted_current_games_with_id(player_id) + |> Enum.map(&format_game_selection_tuple/1) + end + + def refresh_options(%State{options: options}) do + from(g in Game, + where: g.id in ^Enum.map(options, fn {_, id} -> id end), + order_by: [desc: g.id] + ) + |> Repo.all() + |> Repo.preload([:light_player, :dark_player]) + |> Enum.map(&format_game_selection_tuple/1) + end + + def refresh_options(%State{ + options: options, + player_session: %PlayerSession{player_id: player_id} + }) do + previous_last_game_id = + case List.last(options) do + {_label, id} -> id + _ -> 0 + end + + current_screen_games = + get_player_sorted_current_games_with_id(player_id, previous_last_game_id - 1, :asc) + + if !is_nil(current_screen_games) && length(current_screen_games), + do: + current_screen_games + |> Enum.map(&format_game_selection_tuple/1), + else: options + end + + def make_process_tuple(selected_id, %State{ + player_session: player_session + }) do + game = Repo.get(Game, selected_id) + + {Chessh.SSH.Client.Game, + %Chessh.SSH.Client.Game.State{ + player_session: player_session, + game: game + }} + end +end diff --git a/priv/repo/migrations/20230304031125_add_move_history.exs b/priv/repo/migrations/20230304031125_add_move_history.exs new file mode 100644 index 0000000..ce361b6 --- /dev/null +++ b/priv/repo/migrations/20230304031125_add_move_history.exs @@ -0,0 +1,9 @@ +defmodule Chessh.Repo.Migrations.AddMoveHistory do + use Ecto.Migration + + def change do + alter table(:games) do + add(:game_moves, :string, size: 1024) + end + end +end