Skip to content

Commit

Permalink
Add single piece move generation.
Browse files Browse the repository at this point in the history
Single piece move generation can be enabled by adding a square field to
the chess.moves() options object. For example,

  chess.moves({square: 'e2'}) // generates all moves for the piece on e2

Based off code by @jdponomarev.  Fixes #13.
  • Loading branch information
jhlywa committed Dec 14, 2012
1 parent c9be62d commit 9d2489a
Show file tree
Hide file tree
Showing 3 changed files with 86 additions and 12 deletions.
10 changes: 8 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ Using chess.js in a browser is straight-forward:

Using chess.js in node.js is equally easy:

var ch = require('/chess.js')
var ch = require('./chess.js')

var chess = new ch.Chess();
...
Expand Down Expand Up @@ -287,13 +287,19 @@ Or by passing .move() a move object (only the 'to', 'from', and when necessary
// -> { color: 'w', from: 'g2', to: 'g3', flags: 'n', piece: 'p', san: 'g3' }

### .moves([ options ])
Returns a list of all legal moves from the current position. The function be passed a options hash which controls the verbosity of the return values (this may change in the future).
Returns a list of legals moves from the current position. The function takes an optional parameter which controls the single-square move generation and verbosity.

var chess = new Chess();
chess.moves();
// -> ['a3', 'a4', 'b3', 'b4', 'c3', 'c4', 'd3', 'd4', 'e3', 'e4',
'f3', 'f4', 'g3', 'g4', 'h3', 'h4', 'Na3', 'Nc3', 'Nf3', 'Nh3']

chess.moves({square: 'e2'});
// -> ['e3', 'e4']

chess.moves({square: 'e9'}); // invalid square
// -> []

chess.moves({ verbose: true });
// -> [{ color: 'w', from: 'a2', to: 'a3',
flags: 'n', piece: 'p', san 'a3'
Expand Down
32 changes: 22 additions & 10 deletions chess.js
Original file line number Diff line number Diff line change
Expand Up @@ -449,7 +449,7 @@ var Chess = function(fen) {
return move;
}

function generate_moves(settings) {
function generate_moves(options) {
function add_move(board, moves, from, to, flags) {
/* if pawn promotion */
if (board[from].type == PAWN &&
Expand All @@ -468,7 +468,24 @@ var Chess = function(fen) {
var them = swap_color(us);
var second_rank = {b: RANK_7, w: RANK_2};

for (var i = SQUARES.a8; i <= SQUARES.h1; i++) {
var first_sq = SQUARES.a8;
var last_sq = SQUARES.h1;

/* do we want legal moves? */
var legal = (typeof options != 'undefined' && 'legal' in options) ?
options.legal : true;

/* are we generating moves for a single square? */
if (typeof options != 'undefined' && 'square' in options) {
if (options.square in SQUARES) {
first_sq = last_sq = SQUARES[options.square];
} else {
/* invalid square */
return [];
}
}

for (var i = first_sq; i <= last_sq; i++) {
/* did we run off the end of the board */
if (i & 0x88) { i += 7; continue; }

Expand Down Expand Up @@ -557,15 +574,10 @@ var Chess = function(fen) {
}
}

/* if no parameters passed in, assume legal w/ algebraic moves */
if (typeof settings == 'undefined') {
settings = {legal: true};
}

/* return all pseudo-legal moves (this includes moves that allow the king
* to be captured
* to be captured)
*/
if (settings.legal != null && settings.legal == false) {
if (!legal) {
return moves;
}

Expand Down Expand Up @@ -1129,7 +1141,7 @@ var Chess = function(fen) {
* unnecessary move keys resulting from a verbose call.
*/

var ugly_moves = generate_moves();
var ugly_moves = generate_moves(options);
var moves = [];

for (var i = 0, len = ugly_moves.length; i < len; i++) {
Expand Down
56 changes: 56 additions & 0 deletions tests/tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,61 @@ function perft_unit_tests() {
log('');
}

function single_square_move_generation_tests() {
var chess = new Chess();
var start = new Date;
var positions = [
{fen: 'rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1',
square: 'e2', verbose: false, moves: ['e3', 'e4']},
{fen: 'rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1',
square: 'e9', verbose: false, moves: []}, // invalid square
{fen: 'rnbqk1nr/pppp1ppp/4p3/8/1b1P4/2N5/PPP1PPPP/R1BQKBNR w KQkq - 2 3',
square: 'c3', verbose: false, moves: []}, // pinned piece
{fen: '8/k7/8/8/8/8/7p/K7 b - - 0 1',
square: 'h2', verbose: false, moves: ['h1=Q+', 'h1=R+', 'h1=B', 'h1=N']}, // promotion
{fen: 'r1bq1rk1/1pp2ppp/p1np1n2/2b1p3/2B1P3/2NP1N2/PPPBQPPP/R3K2R w KQ - 0 8',
square: 'e1', verbose: false, moves: ['Kf1', 'Kd1', 'O-O', 'O-O-O']}, // castling
{fen: 'r1bq1rk1/1pp2ppp/p1np1n2/2b1p3/2B1P3/2NP1N2/PPPBQPPP/R3K2R w - - 0 8',
square: 'e1', verbose: false, moves: ['Kf1', 'Kd1']}, // no castling
{fen: '8/7K/8/8/1R6/k7/1R1p4/8 b - - 0 1',
square: 'a3', verbose: false, moves: []}, // trapped king
{fen: '8/7K/8/8/1R6/k7/1R1p4/8 b - - 0 1',
square: 'd2', verbose: true,
moves:
[{color:'b', from:'d2', to:'d1', flags:'np', piece:'p', promotion:'q', san:'d1=Q'},
{color:'b', from:'d2', to:'d1', flags:'np', piece:'p', promotion:'r', san:'d1=R'},
{color:'b', from:'d2', to:'d1', flags:'np', piece:'p', promotion:'b', san:'d1=B'},
{color:'b', from:'d2', to:'d1', flags:'np', piece:'p', promotion:'n', san:'d1=N'}]
}, // verbose

];

for (var i = 0; i < positions.length; i++) {
chess.load(positions[i].fen);
var moves = chess.moves({square: positions[i].square, verbose: positions[i].verbose});
var s = 'Single Square Move Generation Test #' + i + ': ' + positions[i].fen + ' ' + positions[i].square + ' : ';

var passed = positions[i].moves.length == moves.length;

for (var j = 0; j < moves.length; j++) {
if (!positions[i].verbose) {
passed = passed && moves[j] == positions[i].moves[j];
} else {
for (var k in moves[j]) {
passed = passed && moves[j][k] == positions[i].moves[j][k];
}
}
}
s += assert(passed);
log(s);
}
var finish = new Date;
var diff = (finish - start) / 1000;

log('--> Single Square Move Generation Time: ' + diff + ' secs ');
log('');
}

function checkmate_unit_tests() {
var chess = new Chess();
var start = new Date;
Expand Down Expand Up @@ -862,6 +917,7 @@ function run_unit_tests() {
}

perft_unit_tests();
single_square_move_generation_tests();
checkmate_unit_tests();
stalemate_unit_tests();
insufficient_material_unit_test();
Expand Down

0 comments on commit 9d2489a

Please sign in to comment.