mirror of
https://github.com/danbee/chess
synced 2025-03-04 08:39:06 +00:00
Players take turns
Restricts players to only be able to move their own pieces and only when it's their turn.
This commit is contained in:
parent
2f1411f075
commit
c0facfa4d5
@ -3,7 +3,7 @@ import _ from "lodash";
|
||||
import $ from "jquery";
|
||||
import classNames from "classnames";
|
||||
|
||||
import { selectPiece, setBoard } from "../store/actions";
|
||||
import { selectPiece, setGame } from "../store/actions";
|
||||
|
||||
class ChessBoardSquare extends React.Component {
|
||||
constructor(props) {
|
||||
@ -16,19 +16,35 @@ class ChessBoardSquare extends React.Component {
|
||||
|
||||
selectSquare() {
|
||||
var { piece, store } = this.props;
|
||||
var { gameId, selectedSquare } = store.getState();
|
||||
var { gameId, selectedSquare, player } = store.getState();
|
||||
|
||||
if (selectedSquare != null) {
|
||||
if (selectedSquare != null && this.moveIsValid()) {
|
||||
$.ajax({
|
||||
method: "PATCH",
|
||||
url: "/api/games/" + gameId,
|
||||
data: { move: { from: selectedSquare, to: this.squareCoords() } }
|
||||
}).then((data) => store.dispatch(setBoard(data)));
|
||||
}).then((data) => store.dispatch(setGame(data)));
|
||||
}
|
||||
else if (piece != undefined) {
|
||||
else if (selectedSquare != null) {
|
||||
store.dispatch(selectPiece(null));
|
||||
}
|
||||
else if (this.playerCanSelectPiece(player, piece)) {
|
||||
store.dispatch(selectPiece(this.squareCoords()));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
moveIsValid() {
|
||||
return !this.isSelectedSquare();
|
||||
}
|
||||
|
||||
playerCanSelectPiece(player, piece) {
|
||||
var { store } = this.props;
|
||||
var { turn } = store.getState();
|
||||
|
||||
return piece != undefined &&
|
||||
piece.colour == player &&
|
||||
player == turn;
|
||||
}
|
||||
|
||||
isSelectedSquare() {
|
||||
var { store } = this.props;
|
||||
|
||||
@ -2,7 +2,7 @@ import React from "react";
|
||||
import _ from "lodash";
|
||||
import $ from "jquery";
|
||||
import { connect } from "react-redux";
|
||||
import { setBoard, setPlayer, setGameId } from "../store/actions";
|
||||
import { setGame, setGameId } from "../store/actions";
|
||||
|
||||
import ChessBoardSquare from "./chess-board-square";
|
||||
|
||||
@ -14,8 +14,7 @@ class ChessBoard extends React.Component {
|
||||
|
||||
$.ajax({ method: "GET", url: `/api/games/${gameId}` })
|
||||
.then((data) => {
|
||||
store.dispatch(setBoard(data.board));
|
||||
store.dispatch(setPlayer(data.player));
|
||||
store.dispatch(setGame(data));
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@ -4,15 +4,12 @@ import defaultState from "../store/default-state";
|
||||
|
||||
const chessBoardReducer = (state = defaultState, action) => {
|
||||
switch (action.type) {
|
||||
case "SET_BOARD":
|
||||
case "SET_GAME":
|
||||
return Immutable.fromJS(state)
|
||||
.set("board", action.board)
|
||||
.set("selectedSquare", null)
|
||||
.toJS();
|
||||
|
||||
case "SET_PLAYER":
|
||||
return Immutable.fromJS(state)
|
||||
.set("player", action.player)
|
||||
.set("turn", action.turn)
|
||||
.set("selectedSquare", null)
|
||||
.toJS();
|
||||
|
||||
case "SET_GAME_ID":
|
||||
|
||||
@ -1,12 +1,13 @@
|
||||
const SET_BOARD = "SET_BOARD";
|
||||
const SET_PLAYER = "SET_PLAYER";
|
||||
const SET_GAME = "SET_GAME";
|
||||
const SET_GAME_ID = "SET_GAME_ID";
|
||||
const SELECT_PIECE = "SELECT_PIECE";
|
||||
|
||||
export const setBoard = (board) => {
|
||||
export const setGame = (data) => {
|
||||
return {
|
||||
type: SET_BOARD,
|
||||
board: board
|
||||
type: SET_GAME,
|
||||
board: data.board,
|
||||
player: data.player,
|
||||
turn: data.turn
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
const defaultState = {
|
||||
selectedSquare: null,
|
||||
|
||||
player: "white",
|
||||
turn: "white",
|
||||
player: null,
|
||||
turn: null,
|
||||
|
||||
board: {
|
||||
8: { a: null, b: null, c: null, d: null, e: null, f: null, g: null, h: null },
|
||||
|
||||
@ -9,6 +9,15 @@ defmodule Chess.Board do
|
||||
end)
|
||||
end
|
||||
|
||||
def move_piece(board, move_params) do
|
||||
[from_file, from_rank] = move_params["from"]
|
||||
[to_file, to_rank] = move_params["to"]
|
||||
|
||||
{piece, board} = Map.pop(board, "#{from_file},#{from_rank}")
|
||||
|
||||
Map.put(board, "#{to_file},#{to_rank}", piece)
|
||||
end
|
||||
|
||||
def default do
|
||||
%{
|
||||
"0,7" => %{type: :rook, colour: :black},
|
||||
|
||||
@ -12,6 +12,7 @@ defmodule Chess.Store.Game do
|
||||
|
||||
schema "games" do
|
||||
field :board, :map
|
||||
field :turn, :string
|
||||
|
||||
belongs_to :user, Chess.Auth.User
|
||||
belongs_to :opponent, Chess.Auth.User, references: :id
|
||||
@ -24,7 +25,8 @@ defmodule Chess.Store.Game do
|
||||
|> cast(params, required_attrs())
|
||||
|> foreign_key_constraint(:user_id)
|
||||
|> foreign_key_constraint(:opponent_id)
|
||||
|> put_change(:board, Board.default)
|
||||
|> put_change(:board, Board.default())
|
||||
|> put_change(:turn, default_turn())
|
||||
|> validate_required(required_attrs())
|
||||
end
|
||||
|
||||
@ -36,6 +38,13 @@ defmodule Chess.Store.Game do
|
||||
|> validate_required(required_attrs())
|
||||
end
|
||||
|
||||
def change_turn(turn) do
|
||||
case turn do
|
||||
"white" -> "black"
|
||||
"black" -> "white"
|
||||
end
|
||||
end
|
||||
|
||||
def for_user(user) do
|
||||
from game in Game,
|
||||
where: game.user_id == ^user.id,
|
||||
@ -47,5 +56,9 @@ defmodule Chess.Store.Game do
|
||||
|> order_by([game], desc: game.inserted_at)
|
||||
end
|
||||
|
||||
defp required_attrs, do: ~w[board user_id opponent_id]a
|
||||
defp required_attrs, do: ~w[board turn user_id opponent_id]a
|
||||
|
||||
defp default_turn do
|
||||
"white"
|
||||
end
|
||||
end
|
||||
|
||||
@ -25,20 +25,24 @@ defmodule ChessWeb.Api.GameController do
|
||||
|> Repo.get!(id)
|
||||
|
||||
changeset = Game.changeset(
|
||||
game, %{board: new_board(game.board, move_params)}
|
||||
game, %{
|
||||
board: Board.move_piece(game.board, move_params),
|
||||
turn: Game.change_turn(game.turn)
|
||||
}
|
||||
)
|
||||
|
||||
case Repo.update(changeset) do
|
||||
{:ok, game} ->
|
||||
conn
|
||||
|> json(Board.transform(game.board))
|
||||
|> json(game_attrs(conn, game))
|
||||
end
|
||||
end
|
||||
|
||||
defp game_attrs(conn, game) do
|
||||
%{
|
||||
board: Board.transform(game.board),
|
||||
player: player(conn, game)
|
||||
player: player(conn, game),
|
||||
turn: game.turn
|
||||
}
|
||||
end
|
||||
|
||||
@ -49,13 +53,4 @@ defmodule ChessWeb.Api.GameController do
|
||||
"black"
|
||||
end
|
||||
end
|
||||
|
||||
defp new_board(board, move_params) do
|
||||
[from_file, from_rank] = move_params["from"]
|
||||
[to_file, to_rank] = move_params["to"]
|
||||
|
||||
{piece, board} = Map.pop(board, "#{from_file},#{from_rank}")
|
||||
|
||||
Map.put(board, "#{to_file},#{to_rank}", piece)
|
||||
end
|
||||
end
|
||||
|
||||
@ -7,6 +7,5 @@ defmodule Chess.Repo.Migrations.CreateGame do
|
||||
|
||||
timestamps()
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
9
priv/repo/migrations/20180223223018_add_turn_to_game.exs
Normal file
9
priv/repo/migrations/20180223223018_add_turn_to_game.exs
Normal file
@ -0,0 +1,9 @@
|
||||
defmodule Chess.Repo.Migrations.AddTurnToGame do
|
||||
use Ecto.Migration
|
||||
|
||||
def change do
|
||||
alter table("games") do
|
||||
add :turn, :string, default: "white"
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -11,7 +11,12 @@ defmodule Chess.GameTest do
|
||||
user = create_user("link", "ilovezelda")
|
||||
opponent = create_user("zelda", "ganonsucks")
|
||||
|
||||
attrs = %{board: %{}, user_id: user.id, opponent_id: opponent.id}
|
||||
attrs = %{
|
||||
board: %{},
|
||||
user_id: user.id,
|
||||
opponent_id: opponent.id,
|
||||
turn: "white"
|
||||
}
|
||||
changeset = Game.changeset(%Game{}, attrs)
|
||||
|
||||
assert changeset.valid?
|
||||
@ -19,7 +24,12 @@ defmodule Chess.GameTest do
|
||||
end
|
||||
|
||||
test "game cannot be saved if the user or opponent do not exist" do
|
||||
attrs = %{board: %{}, user_id: 1, opponent_id: 2}
|
||||
attrs = %{
|
||||
board: %{},
|
||||
user_id: 1,
|
||||
opponent_id: 2,
|
||||
turn: "white"
|
||||
}
|
||||
changeset = Game.changeset(%Game{}, attrs)
|
||||
|
||||
assert changeset.valid?
|
||||
|
||||
Loading…
Reference in New Issue
Block a user