diff options
Diffstat (limited to 'lib/chessh/ssh/client/board')
-rw-r--r-- | lib/chessh/ssh/client/board/board.ex | 123 | ||||
-rw-r--r-- | lib/chessh/ssh/client/board/renderer.ex | 252 | ||||
-rw-r--r-- | lib/chessh/ssh/client/board/server.ex | 19 |
3 files changed, 0 insertions, 394 deletions
diff --git a/lib/chessh/ssh/client/board/board.ex b/lib/chessh/ssh/client/board/board.ex deleted file mode 100644 index cbbade5..0000000 --- a/lib/chessh/ssh/client/board/board.ex +++ /dev/null @@ -1,123 +0,0 @@ -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 diff --git a/lib/chessh/ssh/client/board/renderer.ex b/lib/chessh/ssh/client/board/renderer.ex deleted file mode 100644 index fa8648f..0000000 --- a/lib/chessh/ssh/client/board/renderer.ex +++ /dev/null @@ -1,252 +0,0 @@ -defmodule Chessh.SSH.Client.Board.Renderer do - alias IO.ANSI - alias Chessh.Utils - alias Chessh.SSH.Client.Board - require Logger - - @chess_board_height 8 - @chess_board_width 8 - - @tile_width 7 - @tile_height 4 - - @from_select_background ANSI.light_blue_background() - @to_select_background ANSI.blue_background() - @dark_piece_color ANSI.light_red() - @light_piece_color ANSI.light_magenta() - - def chess_board_height(), do: @chess_board_height - def chess_board_width(), do: @chess_board_width - def to_select_background(), do: @to_select_background - def from_select_background(), do: @from_select_background - - def to_chess_coord({y, x}) - when x >= 0 and x < @chess_board_width and y >= 0 and y < @chess_board_height do - "#{List.to_string([?a + x])}#{@chess_board_height - y}" - end - - def render_board_state(fen, %Board.State{ - width: _width, - height: _height, - highlighted: highlighted, - flipped: flipped - }) do - board = - draw_board( - fen, - {@tile_width, @tile_height}, - highlighted, - flipped - ) - - [ANSI.home()] ++ - Enum.map( - Enum.zip(1..length(board), board), - fn {i, line} -> - [ANSI.cursor(i, 0), line] - end - ) - end - - defp tileIsLight(row, col) do - rem(row, 2) == rem(col, 2) - end - - defp piece_type(char) do - case String.capitalize(char) do - "P" -> "pawn" - "N" -> "knight" - "R" -> "rook" - "B" -> "bishop" - "K" -> "king" - "Q" -> "queen" - _ -> nil - end - end - - defp skip_cols_or_place_piece_reduce(char, {curr_column, data}, rowI) do - case Integer.parse(char) do - {skip, ""} -> - {curr_column + skip, data} - - _ -> - case piece_type(char) do - nil -> - {curr_column, data} - - type -> - shade = if(char == String.capitalize(char), do: "light", else: "dark") - - {curr_column + 1, - Map.put( - data, - "#{rowI}, #{curr_column}", - {shade, type} - )} - end - end - end - - defp make_coordinate_to_piece_art_map(fen) do - rows = - String.split(fen, " ") - |> List.first() - |> String.split("/") - - Enum.zip(rows, 0..(length(rows) - 1)) - |> Enum.map(fn {row, rowI} -> - {@chess_board_height, pieces_per_row} = - Enum.reduce( - String.split(row, ""), - {0, %{}}, - &skip_cols_or_place_piece_reduce(&1, &2, rowI) - ) - - pieces_per_row - end) - |> Enum.reduce(%{}, fn pieces_map_for_this_row, acc -> - Map.merge(acc, pieces_map_for_this_row) - end) - end - - defp draw_board( - fen, - {tile_width, tile_height} = tile_dims, - highlights, - flipped - ) do - coordinate_to_piece = make_coordinate_to_piece_art_map(fen) - board = make_board(tile_dims) - - (Enum.zip_with([board, 0..(length(board) - 1)], fn [row_str, row] -> - curr_y = div(row, tile_height) - - %{row_chars: row_chars} = - Enum.reduce( - Enum.zip(String.graphemes(row_str), 0..(String.length(row_str) - 1)), - %{current_color: ANSI.black(), row_chars: []}, - fn {char, col}, %{current_color: current_color, row_chars: row_chars} = row_state -> - curr_x = div(col, tile_width) - - key = - "#{if !flipped, do: curr_y, else: @chess_board_height - curr_y - 1}, #{if !flipped, do: curr_x, else: @chess_board_width - curr_x - 1}" - - relative_to_tile_col = col - curr_x * tile_width - - prefix = - if relative_to_tile_col == 0 do - case Map.fetch(highlights, {curr_y, curr_x}) do - {:ok, color} -> - color - - _ -> - ANSI.default_background() - end - end - - {color, row_chars} = - case Map.fetch(coordinate_to_piece, key) do - {:ok, {shade, type}} -> - piece = Utils.ascii_chars()["pieces"][shade][type] - piece_line = Enum.at(piece, row - curr_y * tile_height) - pad_left_right = div(tile_width - String.length(piece_line), 2) - - if relative_to_tile_col >= pad_left_right && - relative_to_tile_col < tile_width - pad_left_right do - piece_char = String.at(piece_line, relative_to_tile_col - pad_left_right) - new_char = if piece_char == " ", do: char, else: piece_char - - color = - if piece_char == " ", - do: ANSI.default_color(), - else: - if(shade == "dark", do: @dark_piece_color, else: @light_piece_color) - - if color != current_color do - {color, row_chars ++ [prefix, color, new_char]} - else - {current_color, row_chars ++ [prefix, new_char]} - end - else - {ANSI.default_color(), row_chars ++ [prefix, ANSI.default_color(), char]} - end - - _ -> - if ANSI.default_color() != current_color do - {ANSI.default_color(), row_chars ++ [prefix, ANSI.default_color(), char]} - else - {current_color, row_chars ++ [prefix, char]} - end - end - - %{ - row_state - | current_color: color, - row_chars: row_chars - } - end - ) - - curr_num = - Utils.ascii_chars()["numbers"][ - Integer.to_string(if flipped, do: curr_y + 1, else: @chess_board_height - curr_y) - ] - - curr_num_line_no = rem(row, @tile_height) - - Enum.join( - [ - String.pad_trailing( - if(curr_num_line_no < length(curr_num), - do: Enum.at(curr_num, curr_num_line_no), - else: "" - ), - @tile_width - ) - ] ++ row_chars, - "" - ) - end) ++ column_coords(flipped)) - |> Enum.map(fn row_line -> "#{ANSI.default_background()}#{row_line}" end) - end - - defp column_coords(flipped) do - Enum.map(0..(@tile_height - 1), fn row -> - String.duplicate(" ", @tile_width) <> - (Enum.map( - if(!flipped, do: 0..(@chess_board_width - 1), else: (@chess_board_width - 1)..0), - fn col -> - curr_letter = Utils.ascii_chars()["letters"][List.to_string([?a + col])] - curr_letter_line_no = rem(row, @tile_height) - - curr_line = - if(curr_letter_line_no < length(curr_letter), - do: Enum.at(curr_letter, curr_letter_line_no), - else: "" - ) - - center_prefix_len = div(@tile_width - String.length(curr_line), 2) - - String.pad_trailing( - String.duplicate(" ", center_prefix_len) <> curr_line, - @tile_width - ) - end - ) - |> Enum.join("")) - end) - end - - defp make_board({tile_width, tile_height}) do - rows = - Enum.map(0..(@chess_board_height - 1), fn row -> - Enum.map(0..(@chess_board_width - 1), fn col -> - if(tileIsLight(row, col), do: '▊', else: ' ') - |> List.duplicate(tile_width) - end) - |> Enum.join("") - end) - - Enum.flat_map(rows, fn row -> Enum.map(1..tile_height, fn _ -> row end) end) - end -end diff --git a/lib/chessh/ssh/client/board/server.ex b/lib/chessh/ssh/client/board/server.ex deleted file mode 100644 index 2e480e7..0000000 --- a/lib/chessh/ssh/client/board/server.ex +++ /dev/null @@ -1,19 +0,0 @@ -# defmodule Chessh.SSH.Client.Board.Server do -# use GenServer -# -# defmodule State do -# defstruct game_id: nil, -# binbo_pid: nil -# end -# -# def init([%State{game_id: game_id} = state]) do -# {:ok, binbo_pid} = GenServer.start_link(:binbo, []) -# -# :syn.join(:games, {:game, game_id}) -# {:ok, state} -# end -# -# def handle_cast({:new_move, attempted_move}, %State{game_id: game_id} = state) do -# {:no_reply, state} -# end -# end |