All files gameValidation.js

84.21% Statements 32/38
75% Branches 15/20
77.77% Functions 7/9
86.48% Lines 32/37

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101                      66x       66x         387x 387x   387x 3008x 387x             387x 387x 387x     387x 5181x 5181x     5181x 1x       386x         387x                 387x 387x               387x 387x 387x       387x 387x 387x 387x 387x   387x     387x   387x   387x     387x                
/**
	GameValidation is the 3rd phase of validation for the game
	and is intended to support Game level events. Examples of Game
	scope validation include Check, Checkmate, 3-fold position
	repetition and pawn promotion.
*/
import { BoardValidation } from './boardValidation.js';
import { PieceType } from './piece.js';
 
export class GameValidation {
	constructor (game) {
		this.game = game;
	}
 
	static create (game) {
		return new GameValidation(game);
	}
 
	findKingSquare (side) {
		let
			i = 0,
			squares = this.game.board.getSquares(side);
 
		for (i = 0; i < squares.length; i++) {
			if (squares[i].piece.type === PieceType.King) {
				return squares[i];
			}
		}
	}
 
	isRepetition () {
		let
			hash = '',
			hashCount = [],
			i = 0;
 
		// analyze 3-fold repetition (draw)
		for (i = 0; i < this.game.moveHistory.length; i++) {
			hash = this.game.moveHistory[i].hashCode;
			hashCount[hash] = hashCount[hash] ? hashCount[hash] + 1 : 1;
 
			/* eslint no-magic-numbers: 0 */
			if (hashCount[hash] === 3) {
				return true;
			}
		}
 
		return false;
	}
 
	start (callback) {
		// ensure callback is set
		callback = callback || ((err, result) => new Promise((resolve, reject) => {
			if (err) {
				return reject(err);
			}
 
			return resolve(result);
		}));
 
		let
			kingSquare = null,
			result = {
				isCheck : false,
				isCheckmate : false,
				isFiftyMoveDraw : false,
				isRepetition : false,
				isStalemate : false,
				validMoves : []
			},
			setResult = (v, result, isKingAttacked) => {
				return (err, validMoves) => {
					Iif (err) {
						return callback(err);
					}
 
					result.isCheck = isKingAttacked && validMoves.length > 0;
					result.isCheckmate = isKingAttacked && validMoves.length === 0;
					result.isStalemate = !isKingAttacked && validMoves.length === 0;
					result.isRepetition = v.isRepetition();
					result.validMoves = validMoves;
 
					return callback(null, result);
				};
			},
			v = BoardValidation.create(this.game);
 
		Eif (this.game) {
			// find current side king square
			kingSquare = this.findKingSquare(this.game.getCurrentSide());
 
			// find valid moves
			return v.start(setResult(this, result, v.isSquareAttacked(kingSquare)));
		}
		
		return callback(new Error('game is invalid'));
	}
}
 
export default { GameValidation };