1
0
mirror of https://github.com/danbee/chess synced 2025-03-04 08:39:06 +00:00

Show available moves for pawn

This commit is contained in:
Daniel Barber 2018-03-11 23:21:17 -04:00
parent c64d40f99a
commit 375be4711c
Signed by: danbarber
GPG Key ID: 931D8112E0103DD8
14 changed files with 123 additions and 54 deletions

View File

@ -117,6 +117,11 @@ $board-size: 90vmin;
background-color: mix($black-square-color, $selected-square-color, 60%);
box-shadow: 0 0 0 ($board-size / 400) $selected-outline-color;
}
&.available {
background-color: mix($black-square-color, $available-square-color, 80%);
box-shadow: 0 0 0 ($board-size / 400) $available-outline-color;
}
}
@mixin white-square {
@ -126,6 +131,11 @@ $board-size: 90vmin;
background-color: mix($white-square-color, $selected-square-color, 60%);
box-shadow: 0 0 0 ($board-size / 400) $selected-outline-color;
}
&.available {
background-color: mix($white-square-color, $available-square-color, 80%);
box-shadow: 0 0 0 ($board-size / 400) $available-outline-color;
}
}
.board-rank:nth-child(odd) {

View File

@ -15,10 +15,12 @@ $base-font-size: 16px;
$black-square-color: #777;
$white-square-color: #bbb;
$selected-square-color: #6f0;
$selected-square-color: #0cf;
$available-square-color: #6f0;
$square-outline-color: darken($black-square-color, 20%);
$selected-outline-color: lighten($selected-square-color, 20%);
$available-outline-color: rgba(lighten($available-square-color, 20%), 0.7);
$colours: "black" "white";
$pieces: king queen bishop knight rook pawn;

View File

@ -24,10 +24,6 @@ class App extends React.Component {
this.channel = new Channel(store, gameId);
}
sendMove(gameId, move) {
this.channel.sendMove(move);
}
render() {
const { store, gameId } = this.props;
@ -35,7 +31,7 @@ class App extends React.Component {
<ChessBoard
gameId={gameId}
store={store}
sendMove={this.sendMove.bind(this)}
channel={this.channel}
/>
);
}

View File

@ -4,7 +4,7 @@ import classNames from "classnames";
import API from "../services/api";
import { setGame, selectPiece } from "../store/actions";
import { setGame, setMoves, selectPiece } from "../store/actions";
class ChessBoardSquare extends React.Component {
constructor(props) {
@ -16,23 +16,26 @@ class ChessBoardSquare extends React.Component {
}
selectSquare() {
const { piece, store, sendMove } = this.props;
const { piece, store, channel } = this.props;
const { gameId, selectedSquare, player } = store.getState();
if (selectedSquare != null && this.moveIsValid()) {
sendMove(gameId, {
store.dispatch(setMoves([]));
channel.sendMove({
from: selectedSquare,
to: this.squareCoords,
});
} else if (selectedSquare != null) {
store.dispatch(setMoves([]));
store.dispatch(selectPiece(null));
} else if (this.playerCanSelectPiece(player, piece)) {
channel.getAvailableMoves(this.squareCoords);
store.dispatch(selectPiece(this.squareCoords));
}
}
moveIsValid() {
return !this.isSelectedSquare();
return !this.isSelectedSquare;
}
playerCanSelectPiece(player, piece) {
@ -44,7 +47,7 @@ class ChessBoardSquare extends React.Component {
player == turn;
}
isSelectedSquare() {
get isSelectedSquare() {
const { store } = this.props;
if (store.getState().selectedSquare == null) {
@ -54,19 +57,32 @@ class ChessBoardSquare extends React.Component {
}
}
get isAvailableSquare() {
const { store } = this.props;
const moves = store.getState().moves;
return _.find(moves, function(square) {
return square.join() == this.squareCoords.join();
}.bind(this));
}
squareId() {
return `f${this.props.file}-r${this.props.rank}`;
}
get squareClass() {
if (this.props.piece == undefined) {
return "board-square";
return classNames(
"board-square",
{ "available": this.isAvailableSquare }
);
} else {
return classNames(
"board-square",
this.props.piece.type,
this.props.piece.colour,
{ "selected": this.isSelectedSquare() }
{ "selected": this.isSelectedSquare },
{ "available": this.isAvailableSquare }
);
}
}

View File

@ -26,7 +26,7 @@ class ChessBoard extends React.Component {
}
renderFiles(rankId) {
const { store, sendMove } = this.props;
const { store, channel } = this.props;
const rank = this.getBoard()[rankId];
return _.map(this.files(rank), fileId => {
@ -37,7 +37,7 @@ class ChessBoard extends React.Component {
rank={rankId}
piece={rank[fileId]}
store={store}
sendMove={sendMove}
channel={channel}
/>
);
});

View File

@ -16,6 +16,11 @@ const chessBoardReducer = (state = defaultState, action) => {
.set("selectedSquare", null)
.toJS();
case "SET_MOVES":
return Immutable.fromJS(state)
.set("moves", action.moves)
.toJS();
case "SET_GAME_ID":
return Immutable.fromJS(state)
.set("gameId", action.gameId)

View File

@ -1,5 +1,5 @@
import socket from "../socket";
import { setPlayer, setGame } from "../store/actions";
import { setPlayer, setGame, setMoves } from "../store/actions";
class Channel {
constructor(store, gameId) {
@ -26,6 +26,13 @@ class Channel {
});
}
getAvailableMoves(square) {
this.channel.push("game:get_available_moves", { square })
.receive("ok", (data) => {
this.store.dispatch(setMoves(data.moves));
});
}
sendMove(move) {
this.channel.push("game:move", move);
}

View File

@ -1,5 +1,6 @@
const SET_PLAYER = "SET_PLAYER";
const SET_GAME = "SET_GAME";
const SET_MOVES = "SET_MOVES";
const SET_GAME_ID = "SET_GAME_ID";
const SELECT_PIECE = "SELECT_PIECE";
@ -18,6 +19,13 @@ export const setGame = (data) => {
};
};
export const setMoves = (moves) => {
return {
type: SET_MOVES,
moves,
};
};
export const setGameId = (gameId) => {
return {
type: SET_GAME_ID,

View File

@ -4,6 +4,8 @@ const defaultState = {
player: null,
turn: null,
moves: [],
board: {
8: { a: null, b: null, c: null, d: null, e: null, f: null, g: null, h: null },
7: { a: null, b: null, c: null, d: null, e: null, f: null, g: null, h: null },

View File

@ -20,41 +20,41 @@ defmodule Chess.Board do
def default do
%{
"0,7" => %{type: :rook, colour: :black},
"1,7" => %{type: :knight, colour: :black},
"2,7" => %{type: :bishop, colour: :black},
"3,7" => %{type: :queen, colour: :black},
"4,7" => %{type: :king, colour: :black},
"5,7" => %{type: :bishop, colour: :black},
"6,7" => %{type: :knight, colour: :black},
"7,7" => %{type: :rook, colour: :black},
"0,7" => %{"type" => "rook", "colour" => "black"},
"1,7" => %{"type" => "knight", "colour" => "black"},
"2,7" => %{"type" => "bishop", "colour" => "black"},
"3,7" => %{"type" => "queen", "colour" => "black"},
"4,7" => %{"type" => "king", "colour" => "black"},
"5,7" => %{"type" => "bishop", "colour" => "black"},
"6,7" => %{"type" => "knight", "colour" => "black"},
"7,7" => %{"type" => "rook", "colour" => "black"},
"0,6" => %{type: :pawn, colour: :black},
"1,6" => %{type: :pawn, colour: :black},
"2,6" => %{type: :pawn, colour: :black},
"3,6" => %{type: :pawn, colour: :black},
"4,6" => %{type: :pawn, colour: :black},
"5,6" => %{type: :pawn, colour: :black},
"6,6" => %{type: :pawn, colour: :black},
"7,6" => %{type: :pawn, colour: :black},
"0,6" => %{"type" => "pawn", "colour" => "black"},
"1,6" => %{"type" => "pawn", "colour" => "black"},
"2,6" => %{"type" => "pawn", "colour" => "black"},
"3,6" => %{"type" => "pawn", "colour" => "black"},
"4,6" => %{"type" => "pawn", "colour" => "black"},
"5,6" => %{"type" => "pawn", "colour" => "black"},
"6,6" => %{"type" => "pawn", "colour" => "black"},
"7,6" => %{"type" => "pawn", "colour" => "black"},
"0,1" => %{type: :pawn, colour: :white},
"1,1" => %{type: :pawn, colour: :white},
"2,1" => %{type: :pawn, colour: :white},
"3,1" => %{type: :pawn, colour: :white},
"4,1" => %{type: :pawn, colour: :white},
"5,1" => %{type: :pawn, colour: :white},
"6,1" => %{type: :pawn, colour: :white},
"7,1" => %{type: :pawn, colour: :white},
"0,1" => %{"type" => "pawn", "colour" => "white"},
"1,1" => %{"type" => "pawn", "colour" => "white"},
"2,1" => %{"type" => "pawn", "colour" => "white"},
"3,1" => %{"type" => "pawn", "colour" => "white"},
"4,1" => %{"type" => "pawn", "colour" => "white"},
"5,1" => %{"type" => "pawn", "colour" => "white"},
"6,1" => %{"type" => "pawn", "colour" => "white"},
"7,1" => %{"type" => "pawn", "colour" => "white"},
"0,0" => %{type: :rook, colour: :white},
"1,0" => %{type: :knight, colour: :white},
"2,0" => %{type: :bishop, colour: :white},
"3,0" => %{type: :queen, colour: :white},
"4,0" => %{type: :king, colour: :white},
"5,0" => %{type: :bishop, colour: :white},
"6,0" => %{type: :knight, colour: :white},
"7,0" => %{type: :rook, colour: :white}
"0,0" => %{"type" => "rook", "colour" => "white"},
"1,0" => %{"type" => "knight", "colour" => "white"},
"2,0" => %{"type" => "bishop", "colour" => "white"},
"3,0" => %{"type" => "queen", "colour" => "white"},
"4,0" => %{"type" => "king", "colour" => "white"},
"5,0" => %{"type" => "bishop", "colour" => "white"},
"6,0" => %{"type" => "knight", "colour" => "white"},
"7,0" => %{"type" => "rook", "colour" => "white"}
}
end
end

View File

@ -7,7 +7,7 @@ defmodule Chess.Moves do
piece = board["#{file},#{rank}"]
case piece do
%{type: :pawn} ->
%{"type" => "pawn"} ->
Pawn.moves(board, {file, rank})
end
end

View File

@ -5,12 +5,12 @@ defmodule Chess.Moves.Pawn do
piece = board["#{file},#{rank}"]
case piece do
%{colour: :white} ->
%{"colour" => "white"} ->
case rank do
1 -> [{file, rank + 1}, {file, rank + 2}]
_ -> [{file, rank + 1}]
end
%{colour: :black} ->
%{"colour" => "black"} ->
case rank do
6 -> [{file, rank - 1}, {file, rank - 2}]
_ -> [{file, rank - 1}]

View File

@ -5,6 +5,7 @@ defmodule ChessWeb.GameChannel do
alias Chess.Store.Game
alias Chess.Board
alias Chess.Moves
import Chess.Auth, only: [current_user: 1]
@ -51,6 +52,28 @@ defmodule ChessWeb.GameChannel do
end
end
def handle_in(
"game:get_available_moves",
%{"square" => [file, rank]},
socket
) do
game =
socket.assigns.current_user_id
|> Game.for_user_id()
|> Repo.get!(socket.assigns.game_id)
moves = Moves.available(game.board, {
String.to_integer(file),
String.to_integer(rank)
})
reply = %{
moves: Enum.map(moves, &(Tuple.to_list(&1)))
}
{:reply, {:ok, reply}, socket}
end
def send_update(game) do
payload = %{
board: Board.transform(game.board),

View File

@ -18,7 +18,7 @@ defmodule Chess.Moves.PawnTest do
end
test "white pawn not on starting square can move forward one space" do
board = %{"4,2" => %{type: :pawn, colour: :white}}
board = %{"4,2" => %{"type" => "pawn", "colour" => "white"}}
moves = Pawn.moves(board, {4, 2})
expected_moves = [{4, 3}]
@ -26,7 +26,7 @@ defmodule Chess.Moves.PawnTest do
end
test "black pawn not on starting square can move forward one space" do
board = %{"4,5" => %{type: :pawn, colour: :black}}
board = %{"4,5" => %{"type" => "pawn", "colour" => "black"}}
moves = Pawn.moves(board, {4, 5})
expected_moves = [{4, 4}]