summaryrefslogtreecommitdiff
path: root/lib/chessh/ssh/client/board/board.ex
diff options
context:
space:
mode:
Diffstat (limited to 'lib/chessh/ssh/client/board/board.ex')
-rw-r--r--lib/chessh/ssh/client/board/board.ex123
1 files changed, 123 insertions, 0 deletions
diff --git a/lib/chessh/ssh/client/board/board.ex b/lib/chessh/ssh/client/board/board.ex
new file mode 100644
index 0000000..cbbade5
--- /dev/null
+++ b/lib/chessh/ssh/client/board/board.ex
@@ -0,0 +1,123 @@
+defmodule Chessh.SSH.Client.Board do
+ require Logger
+ alias Chessh.Utils
+ alias Chessh.SSH.Client.Board.Renderer
+
+ defmodule State do
+ defstruct cursor: %{x: 7, y: 7},
+ highlighted: %{},
+ move_from: nil,
+ game_id: nil,
+ client_pid: nil,
+ binbo_pid: nil,
+ width: 0,
+ height: 0,
+ flipped: false
+ end
+
+ use Chessh.SSH.Client.Screen
+
+ def init([%State{client_pid: client_pid, game_id: game_id} = state | _]) do
+ :syn.add_node_to_scopes([:games])
+ :ok = :syn.join(:games, {:game, game_id}, self())
+
+ :binbo.start()
+ {:ok, binbo_pid} = :binbo.new_server()
+ :binbo.new_game(binbo_pid)
+
+ send(client_pid, {:send_to_ssh, Utils.clear_codes()})
+
+ {:ok, %State{state | binbo_pid: binbo_pid}}
+ end
+
+ def handle_info({:new_move, move}, %State{binbo_pid: binbo_pid, client_pid: client_pid} = state) do
+ case :binbo.move(binbo_pid, move) do
+ {:ok, :continue} ->
+ send(client_pid, {:send_to_ssh, render_state(state)})
+
+ _ ->
+ nil
+ end
+
+ {:noreply, state}
+ end
+
+ def input(
+ width,
+ height,
+ action,
+ %State{
+ move_from: move_from,
+ game_id: game_id,
+ cursor: %{x: cursor_x, y: cursor_y} = cursor,
+ client_pid: client_pid,
+ flipped: flipped
+ } = state
+ ) do
+ new_cursor =
+ case action do
+ :left -> %{y: cursor_y, x: Utils.wrap_around(cursor_x, -1, Renderer.chess_board_width())}
+ :right -> %{y: cursor_y, x: Utils.wrap_around(cursor_x, 1, Renderer.chess_board_width())}
+ :down -> %{y: Utils.wrap_around(cursor_y, 1, Renderer.chess_board_height()), x: cursor_x}
+ :up -> %{y: Utils.wrap_around(cursor_y, -1, Renderer.chess_board_height()), x: cursor_x}
+ _ -> cursor
+ end
+
+ {new_move_from, move_to} =
+ if action == :return do
+ coords = {new_cursor.y, new_cursor.x}
+
+ case move_from do
+ nil -> {coords, nil}
+ _ -> {nil, coords}
+ end
+ else
+ {move_from, nil}
+ end
+
+ # TODO: Check move here, then publish new move, subscribers get from DB instead
+ if move_from && move_to do
+ attempted_move =
+ if flipped,
+ do:
+ "#{Renderer.to_chess_coord(flip(move_from))}#{Renderer.to_chess_coord(flip(move_to))}",
+ else: "#{Renderer.to_chess_coord(move_from)}#{Renderer.to_chess_coord(move_to)}"
+
+ :syn.publish(:games, {:game, game_id}, {:new_move, attempted_move})
+ end
+
+ new_state = %State{
+ state
+ | cursor: new_cursor,
+ move_from: new_move_from,
+ highlighted: %{
+ {new_cursor.y, new_cursor.x} => Renderer.to_select_background(),
+ new_move_from => Renderer.from_select_background()
+ },
+ width: width,
+ height: height,
+ flipped: if(action == "f", do: !flipped, else: flipped)
+ }
+
+ send(client_pid, {:send_to_ssh, render_state(new_state)})
+ new_state
+ end
+
+ def render(width, height, %State{client_pid: client_pid} = state) do
+ send(client_pid, {:send_to_ssh, render_state(state)})
+ %State{state | width: width, height: height}
+ end
+
+ def flip({y, x}),
+ do: {Renderer.chess_board_height() - 1 - y, Renderer.chess_board_width() - 1 - x}
+
+ defp render_state(
+ %State{
+ binbo_pid: binbo_pid
+ } = state
+ ) do
+ {:ok, fen} = :binbo.get_fen(binbo_pid)
+
+ Renderer.render_board_state(fen, state)
+ end
+end