Commit 9b59b967 authored by Gerson Sunyé's avatar Gerson Sunyé
Browse files

Added 19 new unit tests for Pawn moves.

parent 0271621a
# Jeu d'échecs en ligne
Ce projet consiste à déployer une application web de jeu d'échecs jouable en multijoueur.
## Installation et lancement
* Récupération du projet, des dépendances et compilation :
```bash
......@@ -10,7 +12,9 @@ Ce projet consiste à déployer une application web de jeu d'échecs jouable en
npm install
tsc
```
* Lancement du serveur :
* Lancement du serveur :
```bash
node build/main.js
```
......@@ -18,8 +22,10 @@ Ce projet consiste à déployer une application web de jeu d'échecs jouable en
* Accès à l'application : http://adresseduserveur:8080 (ou http://localhost:8080 sur le pc local)
## Manuel d'utilisation
Indiquer dans le formulaire en bas de page la pièce à déplacer et sa destination au format `PieceColonneLigne` puis validez.
L'accronyme de la pièce est exprimé selon la liste suivante :
* R : roi
* D : dame
* Fc | Ff : fou initialement en colonne c|f
......@@ -30,6 +36,7 @@ L'accronyme de la pièce est exprimé selon la liste suivante :
>Exemple : PbB4 déplace le pion initialement en colonne B à la case `B4`.
## Organisation des sources
* server : sources relatives au serveur
* `main.ts` : algorithme principale de création et gestion du serveur
* client: sources relatives aux navigateur(s)
......@@ -43,4 +50,5 @@ L'accronyme de la pièce est exprimé selon la liste suivante :
* `.tsconfig` et `package.json` : paramètres de compilation et d'exécution
## API
L'adresse [/status.js](http://localhost:8080/status.js) distribue toutes les informations de la partie en cours.
\ No newline at end of file
......@@ -13,6 +13,7 @@
"author": "Quentin Tonneau",
"license": "MIT",
"dependencies": {
"@types/express": "^4.16.1",
"body-parser": "^1.18.3",
"express": "^4.16.4",
"ts-node": "^8.0.2",
......
import * as isValid from '../src/move-validation'
import * as pieces from '../src/piece'
import { Chessboard, createInitialChessboard, createEmptyChessboard, putPiece } from '../src/chessboard';
import { Position, bottom } from '../src/position';
import { Move, processMove } from '../src/movements';
let chessboard : Chessboard;
let positionA7 : Position = {column: 0, line: 6} // A7
let positionA6 : Position = {column: 0, line: 5} // A6
let positionA5 : Position = {column: 0, line: 4} // A5
let positionA4 : Position = {column: 0, line: 3} // A4
let positionB6 : Position = {column: 1, line: 5} // B6
let positionC6 : Position = {column: 2, line: 5} // C6
let positionC4 : Position = {column: 2, line: 3} // C4
let positionD2 : Position = {column: 3, line: 1} // D2
let positionD3 : Position = {column: 3, line: 2} // D3
let positionD4 : Position = {column: 3, line: 3} // D4
let positionD5 : Position = {column: 3, line: 4} // D5
describe("Test blackPawnMove()", () => {
beforeEach( () => {
chessboard = createInitialChessboard();
})
it("Valid Single foreward A7-A6", () => {
let singleForward: Move = {from: positionA7, to: positionA6, isValid: true}
expect(isValid.blackPawnMove(chessboard, singleForward)).toBeTruthy();
});
it("Valid Double foreward A7-A5", () => {
let doubleForward: Move = {from: positionA7, to: positionA5, isValid: true}
expect(isValid.blackPawnMove(chessboard, doubleForward)).toBeTruthy();
});
it("Invalid Double foreward C6-C4", () => {
processMove(chessboard,"C7-C6");
let doubleForward: Move = {from: positionC6, to: positionC4, isValid: true}
expect(isValid.blackPawnMove(chessboard, doubleForward)).toBeFalsy();
});
it("Invalid Triple foreward A7-A4", () => {
let tripleForward: Move = {from: positionA7, to: positionA4, isValid: true}
expect(isValid.blackPawnMove(chessboard, tripleForward)).toBeFalsy();
});
it("Invalid Single Forward (face-to-face)", () => {
processMove(chessboard,"A2-A4");
processMove(chessboard,"A4-A5");
processMove(chessboard,"A5-A6");
let singleForward: Move = {from: positionA7, to: positionA6, isValid: true}
expect(isValid.blackPawnMove(chessboard, singleForward)).toBeFalsy();
})
it("Invalid Capture Empty Square A7-B6", () => {
let diagonalCapture: Move = {from: positionA7, to: positionB6, isValid: true}
expect(isValid.blackPawnMove(chessboard, diagonalCapture)).toBeFalsy();
});
it("Invalid Capture Same Color A7-B6 ", () => {
processMove(chessboard,"B7-B6");
let diagonalCapture: Move = {from: positionA7, to: positionB6, isValid: true}
expect(isValid.blackPawnMove(chessboard, diagonalCapture)).toBeFalsy();
});
it("Valid Capture A7-B6", () => {
processMove(chessboard,"B2-B4");
processMove(chessboard,"B4-B5");
processMove(chessboard,"B5-B6");
let diagonalCapture: Move = {from: positionA7, to: positionB6, isValid: true}
expect(isValid.blackPawnMove(chessboard, diagonalCapture)).toBeTruthy();
});
});
describe("Test whitePawnMove()", () => {
beforeEach( () => {
chessboard = createEmptyChessboard();
})
it("Invalid face to face forward", () => {
putPiece(chessboard, 3, 3, pieces.whitePawn); // White Pawn at D4
putPiece(chessboard, 3, 4, pieces.blackPawn); // Black Pawn at D5
let simpleFowardMove: Move = {from: positionD4, to: positionD5, isValid: true}
expect(isValid.whitePawnMove(chessboard, simpleFowardMove)).toBeFalsy();
});
it("Valid simple forward", () => {
putPiece(chessboard, 3, 3, pieces.whitePawn); // White Pawn at D4
let simpleFowardMove: Move = {from: positionD4, to: positionD5, isValid: true}
expect(isValid.whitePawnMove(chessboard, simpleFowardMove)).toBeTruthy();
});
it("Valid double forward", () => {
putPiece(chessboard, 3, 1, pieces.whitePawn); // White Pawn at D2
let doubleFowardMove: Move = {from: positionD2, to: positionD4, isValid: true}
expect(isValid.whitePawnMove(chessboard, doubleFowardMove)).toBeTruthy();
});
it("Invalid double forward", () => {
putPiece(chessboard, 3, 2, pieces.whitePawn); // White Pawn at D3
let doubleFowardMove: Move = {from: positionD3, to: positionD5, isValid: true}
expect(isValid.whitePawnMove(chessboard, doubleFowardMove)).toBeFalsy();
});
it("Invalid capture empty square", () => {
putPiece(chessboard, 3, 2, pieces.whitePawn); // White Pawn at D3
let diagonalCapture: Move = {from: positionD3, to: positionC4, isValid: true}
expect(isValid.whitePawnMove(chessboard, diagonalCapture)).toBeFalsy();
});
it("Invalid capture same color", () => {
putPiece(chessboard, 3, 2, pieces.whitePawn); // White Pawn at D3
putPiece(chessboard, 2, 3, pieces.whitePawn); // White Pawn at C4
let diagonalCapture: Move = {from: positionD3, to: positionC4, isValid: true}
expect(isValid.whitePawnMove(chessboard, diagonalCapture)).toBeFalsy();
});
it("Valid capture", () => {
putPiece(chessboard, 3, 2, pieces.whitePawn); // White Pawn at D3
putPiece(chessboard, 2, 3, pieces.blackKing); // Black King at C4
let diagonalCapture: Move = {from: positionD3, to: positionC4, isValid: true}
expect(isValid.whitePawnMove(chessboard, diagonalCapture)).toBeTruthy();
})
});
\ No newline at end of file
......@@ -7,24 +7,24 @@ describe("parseMoveString", () => {
let expectedFrom: Position = {column: 0, line:1}
let expectedTo: Position = {column:0, line:3}
expect(move.isValid).toBeTruthy();
expect(equals(expectedFrom, move.from)).toBeTruthy();
expect(equals(expectedTo, move.to)).toBeTruthy();
expect(equals(expectedFrom, move.from!)).toBeTruthy();
expect(equals(expectedTo, move.to!)).toBeTruthy();
});
it("B8-B3", () => {
let move: Move = parseMoveString("B8-B3");
let expectedFrom: Position = {column: 1, line:7}
let expectedTo: Position = {column:1, line:2}
expect(move.isValid).toBeTruthy();
expect(equals(expectedFrom, move.from)).toBeTruthy();
expect(equals(expectedTo, move.to)).toBeTruthy();
expect(equals(expectedFrom, move.from!)).toBeTruthy();
expect(equals(expectedTo, move.to!)).toBeTruthy();
});
it("H8-H3", () => {
let move: Move = parseMoveString("H8-H3");
let expectedFrom: Position = {column: 7, line:7}
let expectedTo: Position = {column:7, line:2}
expect(move.isValid).toBeTruthy();
expect(equals(expectedFrom, move.from)).toBeTruthy();
expect(equals(expectedTo, move.to)).toBeTruthy();
expect(equals(expectedFrom, move.from!)).toBeTruthy();
expect(equals(expectedTo, move.to!)).toBeTruthy();
});
it("a1-h8 == A1-H8", () => {
let lowercaseMove: Move = parseMoveString("a1-h8");
......@@ -33,8 +33,8 @@ describe("parseMoveString", () => {
expect(lowercaseMove.isValid).toBeTruthy();
expect(uppercaseMove.isValid).toBeTruthy();
expect(equals(lowercaseMove.from, uppercaseMove.from)).toBeTruthy();
expect(equals(lowercaseMove.to, uppercaseMove.to)).toBeTruthy();
expect(equals(lowercaseMove.from!, uppercaseMove.from!)).toBeTruthy();
expect(equals(lowercaseMove.to!, uppercaseMove.to!)).toBeTruthy();
});
})
\ No newline at end of file
......@@ -20,19 +20,19 @@ export function isEmpty(chessboard : Chessboard, position : Position): boolean {
export function emptyColumn(chessboard : Chessboard, move: Move): boolean {
let start: number;
let end : number;
let column : number = move.from.column;
let column : number = move.from!.column;
if (column !== move.to.column) {
if (column !== move.to!.column) {
//should not happen
return false;
}
if (move.from.line > move.to.line) {
start = move.to.line;
end = move.from.line;
if (move.from!.line > move.to!.line) {
start = move.to!.line;
end = move.from!.line;
} else {
end = move.to.line;
start = move.from.line;
end = move.to!.line;
start = move.from!.line;
}
let i : number = start;
......@@ -56,32 +56,27 @@ export interface Chessboard {
}
export function squareAtPosition(chessboard: Chessboard, position : Position): Square {
console.log(JSON.stringify(position));
let square: Square = chessboard.board[position.column][position.line];
console.log(JSON.stringify(square));
return square;
}
export function pieceAtPosition(chessboard: Chessboard, position : Position): Piece {
let square: Square = squareAtPosition(chessboard, position);
return square.piece;
return square.piece!;
}
/** Retourne un échiquier initialisé en début de partie **/
export function createChessboard(): Chessboard {
export function createInitialChessboard(): Chessboard {
let chessboard : Chessboard = createChessboard();
let board : Square[][] = []
for (let i = 0; i < 8; i++) {
board[i] = [];
}
// Lines 2 - 6 are empty
for(let line: number = 2; line < 6; line++) {
for(let col: number = 0; col < 8; col++) {
let position: Position = {line : line, column : col};
let square : Square = {position : position, isEmpty : true};
board[col][line] = square;
chessboard.board[col][line] = square;
}
}
......@@ -89,33 +84,56 @@ export function createChessboard(): Chessboard {
let position: Position;
let square : Square;
for(let col: number = 0; col < 8; col++) {
putSquare(board, 1, col, pieces.whitePawn);
putSquare(board, 6, col, pieces.blackPawn);
putPiece(chessboard, col, 1, pieces.whitePawn);
putPiece(chessboard, col, 6, pieces.blackPawn);
}
// Kings and Queens
putSquare(board, 0, 3, pieces.whiteKing);
putSquare(board, 7, 3, pieces.blackKing);
putSquare(board, 0, 4, pieces.whiteQueen);
putSquare(board, 7, 4, pieces.blackQueen);
putPiece(chessboard, 3, 0, pieces.whiteKing);
putPiece(chessboard, 3, 7, pieces.blackKing);
putPiece(chessboard, 4, 0, pieces.whiteQueen);
putPiece(chessboard, 4, 7, pieces.blackQueen);
// Bishops
putSquare(board, 0, 2, pieces.whiteBishop);
putSquare(board, 7, 2, pieces.blackBishop);
putSquare(board, 0, 5, pieces.whiteBishop);
putSquare(board, 7, 5, pieces.blackBishop);
putPiece(chessboard, 2, 0, pieces.whiteBishop);
putPiece(chessboard, 2, 7, pieces.blackBishop);
putPiece(chessboard, 5, 0, pieces.whiteBishop);
putPiece(chessboard, 5, 7, pieces.blackBishop);
// Knights
putSquare(board, 0, 1, pieces.whiteKnight);
putSquare(board, 7, 1, pieces.blackKnight);
putSquare(board, 0, 6, pieces.whiteKnight);
putSquare(board, 7, 6, pieces.blackKnight);
putPiece(chessboard, 1, 0, pieces.whiteKnight);
putPiece(chessboard, 1, 7, pieces.blackKnight);
putPiece(chessboard, 6, 0, pieces.whiteKnight);
putPiece(chessboard, 6, 7, pieces.blackKnight);
// Roocks
putSquare(board, 0, 0, pieces.whiteRoock);
putSquare(board, 7, 0, pieces.blackRoock);
putSquare(board, 0, 7, pieces.whiteRoock);
putSquare(board, 7, 7, pieces.blackRoock);
putPiece(chessboard, 0, 0, pieces.whiteRoock);
putPiece(chessboard, 0, 7, pieces.blackRoock);
putPiece(chessboard, 7, 0, pieces.whiteRoock);
putPiece(chessboard, 7, 7, pieces.blackRoock);
return chessboard;
}
export function createEmptyChessboard(): Chessboard {
let newChessboard : Chessboard = createChessboard();
for(let line: number = 0; line < 8; line++) {
for(let col: number = 0; col < 8; col++) {
let position: Position = {line : line, column : col};
let square : Square = {position : position, isEmpty : true};
newChessboard.board[col][line] = square;
}
}
return newChessboard;
}
function createChessboard(): Chessboard {
let board : Square[][] = []
for (let i = 0; i < 8; i++) {
board[i] = [];
}
let newChessboard : Chessboard = {
nbCoups:0,
......@@ -123,9 +141,11 @@ export function createChessboard(): Chessboard {
historique:[]
};
return newChessboard;
}
function putSquare(board : Array<Array<Square>>, line: number, column : number, piece : Piece) {
export function putPiece(chessboard: Chessboard, column : number, line: number, piece : Piece) {
let board : Array<Array<Square>> = chessboard.board;
let position : Position = {line : line, column : column};
let square : Square = {position : position, isEmpty : false, piece : piece};
board[column][line] = square;
......
import express = require('express');
import bodyParser = require('body-parser');
......@@ -6,7 +5,7 @@ const PORT: number = 8080;
const PUBLIC_DIR = 'client'
const app = express();
import { Chessboard, createChessboard } from './chessboard';
import { Chessboard, createInitialChessboard } from './chessboard';
import { processMove } from './movements';
......@@ -18,21 +17,21 @@ class HttpServer {
}
public onStart(): void {
let chessboard: Chessboard = createChessboard();
let chessboard: Chessboard = createInitialChessboard();
let app: express.Application = express();
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(express.static(PUBLIC_DIR));
app.listen(this.port, () => {
console.log('Application lancée à l\'adresse http://localhost:' + this.port);
console.log("Application lancée à l'adresse http://localhost:" + this.port);
});
app.get("/status.js", (req, res) => {
app.get("/status.js", (req: express.Request, res: express.Response) => {
res.end("var boardJSON= "+JSON.stringify(chessboard));
});
app.post("/", (req, res) => {
app.post("/", (req: express.Request, res: express.Response) => {
let coup : string = req.body.coup;
chessboard = processMove(chessboard, coup);
res.redirect("/");
......
import { Chessboard, isEmpty, Square, squareAtPosition } from "./chessboard";
import { Move } from "./movements";
import { equals, left, right, bottom, top } from "./position";
export function blackPawnMove(board : Chessboard, move : Move) {
// #TODO: Manage special 'En passant' move.
if (equals(move.to!, top(move.from!))) {
//console.log("Single forward");
return isEmpty(board, move.to!);
}
if (move.from!.line === 6 && equals(move.to!, top(top(move.from!)))) {
//console.log("Double forward");
return isEmpty(board, top(move.from!)) && isEmpty(board, move.to!);
}
if (equals(move.to!, left(top(move.from!))) || equals(move.to!, right(top(move.from!)))) {
let destination: Square = squareAtPosition(board, move.to!);
return !(destination.isEmpty || !destination.piece!.isWhite)
}
return false;
}
export function blackKingMove(board : Chessboard, move : Move) {
// #TODO: Implement this function
return true;
}
export function blackQueenMove(board : Chessboard, move : Move) {
// #TODO: Implement this function
return true;
}
export function blackRoockMove(board : Chessboard, move : Move) {
// #TODO: Implement this function
return true;
}
export function blackBishopMove(board : Chessboard, move : Move) {
// #TODO: Implement this function
return true;
}
export function blackKnightMove(board : Chessboard, move : Move) {
// #TODO: Implement this function
return true;
}
export function whitePawnMove(board : Chessboard, move : Move) {
// #TODO: Manage special 'En passant' move.
if (equals(move.to!,bottom(move.from!))) {
return isEmpty(board, move.to!);
}
if (move.from!.line === 1 && equals(move.to!, bottom(bottom(move.from!)))) {
return isEmpty(board, bottom(move.from!)) && isEmpty(board, move.to!);
}
if (equals(move.to!, left(bottom(move.from!))) || equals(move.to!, right(bottom(move.from!)))) {
let destination: Square = squareAtPosition(board, move.to!);
return !(destination.isEmpty || destination.piece!.isWhite)
}
return false;
}
export function whiteKingMove(board : Chessboard, move : Move) {
// #TODO: Implement this function
return true;
}
export function whiteQueenMove(board : Chessboard, move : Move) {
// #TODO: Implement this function
return true;
}
export function whiteRoockMove(board : Chessboard, move : Move) {
// #TODO: Implement this function
return true;
}
export function whiteBishopMove(board : Chessboard, move : Move) {
// #TODO: Implement this function
return true;
}
export function whiteKnightMove(board : Chessboard, move : Move) {
// #TODO: Implement this function
return true;
}
\ No newline at end of file
import { Chessboard, squareAtPosition, Square, pieceAtPosition, isEmpty } from './chessboard'
import { Position, top, bottom, right, left, equals } from "./position";
import * as pieces from './piece'
import {Piece} from './piece'
import * as isValid from './move-validation'
const VALID_MOVE_STRING: RegExp = new RegExp('([a-z]|[A-Z])([1-8])-([A-H]|[a-z])([1-8])')
......@@ -14,8 +14,7 @@ export interface Move {
export function processMove(chessboard:Chessboard, movementString: string): Chessboard {
let move : Move = parseMoveString(movementString);
console.log("Move: " + move.from.column + move.from.line +
move.to.column + move.to.line);
//console.log("Move: " + move.from.column + move.from.line + move.to.column + move.to.line);
if (move.isValid && isMovePossible(chessboard, move)) {
performMove(chessboard, move);
......@@ -47,78 +46,45 @@ export function parseMoveString(movementString: string): Move {
}
function isMovePossible(chessboard : Chessboard, move : Move): boolean {
let square: Square = squareAtPosition(chessboard, move.from);
if (square.isEmpty) {
console.log("Empty from");
return false;
}
let square: Square = squareAtPosition(chessboard, move.from!);
if (square.isEmpty) { return false;}
let piece : Piece = square.piece;
let piece : Piece = square.piece!;
switch(piece) {
case pieces.whitePawn : return isValidWhitePawnMove(chessboard, move);
case pieces.blackPawn : {
console.log("Black pawn");
return isValidBlackPawnMove(chessboard, move);
}
case pieces.whitePawn : return isValid.whitePawnMove(chessboard, move);
case pieces.whiteKing : return isValid.whiteKingMove(chessboard, move);
case pieces.whiteQueen : return isValid.whiteQueenMove(chessboard, move);
case pieces.whiteBishop: return isValid.whiteBishopMove(chessboard, move);
case pieces.whiteKnight: return isValid.whiteKnightMove(chessboard, move);
case pieces.whiteRoock : return isValid.whiteRoockMove(chessboard, move);
case pieces.blackPawn : return isValid.blackPawnMove(chessboard, move);
case pieces.blackKing : return isValid.blackKingMove(chessboard, move);
case pieces.blackQueen : return isValid.blackQueenMove(chessboard, move);
case pieces.blackBishop: return isValid.blackBishopMove(chessboard, move);
case pieces.blackKnight: return isValid.blackKnightMove(chessboard, move);
case pieces.blackRoock : return isValid.blackRoockMove(chessboard, move);
}
return true;
return false;
}
function performMove(board : Chessboard, move : Move) {
let source : Square = squareAtPosition(board, move.from);
let destination : Square = squareAtPosition(board, move.to);
let source : Square = squareAtPosition(board, move.from!);
let destination : Square = squareAtPosition(board, move.to!);
destination.piece = source.piece;
destination.isEmpty = false;
source.isEmpty = true;
}
function isValidBlackPawnMove(board : Chessboard, move : Move) {
// #TODO: Manage special 'En passant' move.
if (equals(move.to, top(move.from))) {
console.log("Single forward");
return isEmpty(board, move.to);
}
if (move.from.line === 6 && equals(move.to, top(top(move.from)))) {
console.log("Double forward");