defmodule Chessh.SSH.Client.PreviousGame do @start_fen "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1" alias Chessh.{Game, Utils} alias Chessh.SSH.Client.Game.Renderer alias IO.ANSI require Logger defmodule State do defstruct move_fens: %{}, move_idx: 0, binbo_pid: nil, game: %Game{}, client_pid: nil, flipped: false end use Chessh.SSH.Client.Screen def init([ %State{ client_pid: client_pid, game: %Game{ game_moves: game_moves } } = state ]) do {:ok, binbo_pid} = :binbo.new_server() :binbo.new_game(binbo_pid, @start_fen) {move_fens, _moves} = game_moves |> String.trim() |> String.split(" ") |> Enum.reduce({%{"0" => @start_fen}, 1}, fn move, {move_idx_fen_map, curr_turn} -> {:ok, _status} = :binbo.move(binbo_pid, move) {:ok, fen} = :binbo.get_fen(binbo_pid) {Map.put(move_idx_fen_map, "#{curr_turn}", fen), curr_turn + 1} end) new_state = %State{ state | binbo_pid: binbo_pid, move_fens: move_fens } send(client_pid, {:send_to_ssh, Utils.clear_codes()}) render(new_state) {:ok, new_state} end def input( _width, _height, action, %State{ move_idx: move_idx, flipped: flipped, game: %Game{ moves: num_moves } } = state ) do new_move_idx = case action do :left -> Utils.wrap_around(move_idx, -1, num_moves) :right -> Utils.wrap_around(move_idx, 1, num_moves) _ -> move_idx end new_state = %State{ state | move_idx: new_move_idx, flipped: if(action == "f", do: !flipped, else: flipped) } render(new_state) new_state end def render( %State{ flipped: flipped, client_pid: client_pid, move_fens: move_fens, move_idx: move_idx, game: %Game{id: game_id, moves: total_moves} } = state ) do {:ok, fen} = Map.fetch(move_fens, "#{move_idx}") lines = ["Game #{game_id} | Move #{move_idx} / #{total_moves}"] ++ Renderer.draw_board(fen, flipped) ++ ["<- previous | next ->"] send( client_pid, {:send_to_ssh, [ANSI.home()] ++ Enum.map( Enum.zip(1..length(lines), lines), fn {i, line} -> [ANSI.cursor(i, 0), ANSI.clear_line(), line] end )} ) state end def render(_width, _height, %State{} = state), do: render(state) end