Permalink
Browse files

- renamed variables in pgn() from camel-case to underscore notation.

- added an info() function that takes PGN header information.
- updated pgn() to output header information.
- updated pgn() to optionally take a maximum width and a newline character.
- added tests for pgn(), which also tests info().
  • Loading branch information...
1 parent c3737e5 commit 84991c99725cb5e16c68f662bfbef62c3c572f5f @2sb18 committed Jun 17, 2011
Showing with 130 additions and 14 deletions.
  1. +67 −14 chess.js
  2. +63 −0 tests/tests.js
View
@@ -147,6 +147,7 @@ var Chess = function(fen) {
var half_moves = 0;
var move_number = 1;
var history = [];
+ var info = {}; // holds PGN header information.
/* if the user passes in a fen string, load it, else default to
* starting position
@@ -166,6 +167,7 @@ var Chess = function(fen) {
half_moves = 0;
move_number = 1;
history = [];
+ info = {};
}
function reset() {
@@ -274,27 +276,71 @@ var Chess = function(fen) {
}
// using the specification from http://www.chessclub.com/help/PGN-spec
- function generate_pgn() {
- var i = 0;
+ // options_obj can contain the maxium width and a newline character
+ // example for html usage: options_obj = {max_width:72, newline_char:"<br />"}
+ function generate_pgn(options_obj) {
var result = [];
- var currentMove;
- var currentMoveNumber = 1;
+ var move_strings = [];
+ var move_string = "";
+ var current_move_number = 1;
+ var newline_char = (typeof options_obj === "object" && typeof options_obj.newline_char === "string") ? options_obj.newline_char : "\n";
+ var max_width = (typeof options_obj === "object" && typeof options_obj.max_width === "number") ? options_obj.max_width : 0;
+ var current_width = 0;
+
+ // add the PGN header information
+ for (var i in info) {
+ result.push("[" + i + " \"" + info[i] + "\"]" + newline_char);
+ }
+ result.push(newline_char);
// pop all of history onto reversedHistory
- var reversedHistory = [];
+ var reversed_history = [];
while (history.length > 0) {
- reversedHistory.push(undo_move());
+ reversed_history.push(undo_move());
}
- while(reversedHistory.length > 0) {
- history.length % 2 === 0 ? result.push(currentMoveNumber++ + ".") : null;
- currentMove = reversedHistory.pop();
- result.push(move_to_san(currentMove));
- make_move(currentMove);
+ // fill the array of move_strings. Example of a move_string: "3. e3 e6"
+ while(reversed_history.length > 0) {
+ if (history.length % 2 === 0) {
+ move_string.length ? move_strings.push(move_string) : null;
+ move_string = current_move_number + ".";
+ current_move_number++;
+ }
+ var current_move = reversed_history.pop();
+ move_string = move_string + " " + move_to_san(current_move);
+ make_move(current_move);
}
+ move_string.length ? move_strings.push(move_string) : null;
// history should be back to what is was before we started generating pgn
- return result.join(" ");
+
+ // join together move_strings
+ if (max_width === 0) {
+ return result.join("") + move_strings.join(" ");
+ }
+
+ for (var i = 0; i < move_strings.length; i++) {
+ if (current_width + move_strings[i].length > max_width && i !== 0) {
+ result.push(newline_char);
+ current_width = 0;
+ } else if (i !== 0) {
+ result.push(" ");
+ current_width++;
+ }
+ result.push(move_strings[i]);
+ current_width += move_strings[i].length;
+ }
+ return result.join("");
+ }
+
+ // ex. set_info('White', 'Jeff Hlywa', 'Black', 'Steve Bragg')
+ function set_info(args) {
+ for (var i = 0; i < args.length; i += 2) {
+ if (typeof args[i] === "string" && typeof args[i + 1] === "string") {
+ info[args[i]] = args[i + 1];
+ }
+ }
+ return info;
}
function get(square) {
@@ -1076,8 +1122,14 @@ var Chess = function(fen) {
return generate_fen();
},
- pgn: function() {
- return generate_pgn();
+ // options_obj can contain width and a newline character
+ // example for html usage: options_obj = {max_width:72, newline_char:"<br />"}
+ pgn: function(options_obj) {
+ return generate_pgn(options_obj);
+ },
+
+ info: function() {
+ return set_info(arguments);
},
ascii: function() {
@@ -1177,3 +1229,4 @@ var Chess = function(fen) {
/* export Chess object if using node or any other CommonJS compatible
* environment */
if (typeof exports != 'undefined') exports.Chess = Chess;
+
View
@@ -356,6 +356,68 @@ function fen_tests() {
log('');
}
+function pgn_tests() {
+ var chess = new Chess();
+ var start = new Date;
+ var passed = true;
+ var error_message;
+ var positions = [
+ {moves: ['d4', 'd5', 'Nf3', 'Nc6', 'e3', 'e6', 'Bb5', 'g5', 'O-O', 'Qf6', 'Nc3',
+ 'Bd7', 'Bxc6', 'Bxc6', 'Re1', 'O-O-O', 'a4', 'Bb4', 'a5', 'b5', 'axb6',
+ 'axb6', 'Ra8+', 'Kd7', 'Ne5+', 'Kd6', 'Rxd8+', 'Qxd8', 'Nxf7+', 'Ke7',
+ 'Nxd5+', 'Qxd5', 'c3', 'Kxf7', 'Qf3+', 'Qxf3', 'gxf3', 'Bxf3', 'cxb4',
+ 'e5', 'dxe5', 'Ke6', 'b3', 'Kxe5', 'Bb2+', 'Ke4', 'Bxh8', 'Nf6', 'Bxf6',
+ 'h5', 'Bxg5', 'Bg2', 'Kxg2', 'Kf5', 'Bh4', 'Kg4', 'Bg3', 'Kf5', 'e4+',
+ 'Kg4', 'e5', 'h4', 'Bxh4', 'Kxh4', 'e6', 'c5', 'bxc5', 'bxc5', 'e7', 'c4',
+ 'bxc4', 'Kg4', 'e8=Q', 'Kf5', 'Qe5+', 'Kg4', 'Re4#'],
+ info: ['White', 'Jeff Hlywa', 'Black', 'Steve Bragg', 'GreatestGameEverPlayed?', 'True'],
+ max_width:19,
+ newline_char:"<br />",
+ pgn: '[White "Jeff Hlywa"]<br />[Black "Steve Bragg"]<br />[GreatestGameEverPlayed? "True"]<br /><br />1. d4 d5 2. Nf3 Nc6<br />3. e3 e6 4. Bb5 g5<br />5. O-O Qf6<br />6. Nc3 Bd7<br />7. Bxc6 Bxc6<br />8. Re1 O-O-O<br />9. a4 Bb4 10. a5 b5<br />11. axb6 axb6<br />12. Ra8+ Kd7<br />13. Ne5+ Kd6<br />14. Rxd8+ Qxd8<br />15. Nxf7+ Ke7<br />16. Nxd5+ Qxd5<br />17. c3 Kxf7<br />18. Qf3+ Qxf3<br />19. gxf3 Bxf3<br />20. cxb4 e5<br />21. dxe5 Ke6<br />22. b3 Kxe5<br />23. Bb2+ Ke4<br />24. Bxh8 Nf6<br />25. Bxf6 h5<br />26. Bxg5 Bg2<br />27. Kxg2 Kf5<br />28. Bh4 Kg4<br />29. Bg3 Kf5<br />30. e4+ Kg4<br />31. e5 h4<br />32. Bxh4 Kxh4<br />33. e6 c5<br />34. bxc5 bxc5<br />35. e7 c4<br />36. bxc4 Kg4<br />37. e8=Q Kf5<br />38. Qe5+ Kg4<br />39. Re4#',
+ fen: '8/8/8/4Q3/2P1R1k1/8/5PKP/8 b - - 4 39'},
+ {moves: ['c4', 'e6', 'Nf3', 'd5', 'd4', 'Nf6', 'Nc3', 'Be7', 'Bg5', 'O-O', 'e3', 'h6',
+ 'Bh4', 'b6', 'cxd5', 'Nxd5', 'Bxe7', 'Qxe7', 'Nxd5', 'exd5', 'Rc1', 'Be6',
+ 'Qa4', 'c5', 'Qa3', 'Rc8', 'Bb5', 'a6', 'dxc5', 'bxc5', 'O-O', 'Ra7',
+ 'Be2', 'Nd7', 'Nd4', 'Qf8', 'Nxe6', 'fxe6', 'e4', 'd4', 'f4', 'Qe7',
+ 'e5', 'Rb8', 'Bc4', 'Kh8', 'Qh3', 'Nf8', 'b3', 'a5', 'f5', 'exf5',
+ 'Rxf5', 'Nh7', 'Rcf1', 'Qd8', 'Qg3', 'Re7', 'h4', 'Rbb7', 'e6', 'Rbc7',
+ 'Qe5', 'Qe8', 'a4', 'Qd8', 'R1f2', 'Qe8', 'R2f3', 'Qd8', 'Bd3', 'Qe8',
+ 'Qe4', 'Nf6', 'Rxf6', 'gxf6', 'Rxf6', 'Kg8', 'Bc4', 'Kh8', 'Qf4'],
+ info: ["Event", "Reykjavik WCh", "Site", "Reykjavik WCh", "Date", "1972.01.07", "EventDate", "?", "Round", "6", "Result", "1-0",
+ "White", "Robert James Fischer", "Black", "Boris Spassky", "ECO", "D59", "WhiteElo", "?", "BlackElo", "?", "PlyCount", "81"],
+ max_width:65,
+ pgn: '[Event "Reykjavik WCh"]\n[Site "Reykjavik WCh"]\n[Date "1972.01.07"]\n[EventDate "?"]\n[Round "6"]\n[Result "1-0"]\n[White "Robert James Fischer"]\n[Black "Boris Spassky"]\n[ECO "D59"]\n[WhiteElo "?"]\n[BlackElo "?"]\n[PlyCount "81"]\n\n1. c4 e6 2. Nf3 d5 3. d4 Nf6 4. Nc3 Be7 5. Bg5 O-O 6. e3 h6\n7. Bh4 b6 8. cxd5 Nxd5 9. Bxe7 Qxe7 10. Nxd5 exd5 11. Rc1 Be6\n12. Qa4 c5 13. Qa3 Rc8 14. Bb5 a6 15. dxc5 bxc5 16. O-O Ra7\n17. Be2 Nd7 18. Nd4 Qf8 19. Nxe6 fxe6 20. e4 d4 21. f4 Qe7\n22. e5 Rb8 23. Bc4 Kh8 24. Qh3 Nf8 25. b3 a5 26. f5 exf5\n27. Rxf5 Nh7 28. Rcf1 Qd8 29. Qg3 Re7 30. h4 Rbb7 31. e6 Rbc7\n32. Qe5 Qe8 33. a4 Qd8 34. R1f2 Qe8 35. R2f3 Qd8 36. Bd3 Qe8\n37. Qe4 Nf6 38. Rxf6 gxf6 39. Rxf6 Kg8 40. Bc4 Kh8 41. Qf4',
+ fen: '4q2k/2r1r3/4PR1p/p1p5/P1Bp1Q1P/1P6/6P1/6K1 b - - 4 41'},
+ {moves: ['f3', 'e5', 'g4', 'Qh4#'],
+ info: ["White", "child", "Black", "Steve Bragg", "Steve'sComment", "It's not fair"],
+ max_width:1,
+ pgn: '[White "child"]\n[Black "Steve Bragg"]\n[Steve\'sComment "It\'s not fair"]\n\n1. f3 e5\n2. g4 Qh4#',
+ fen: 'rnb1kbnr/pppp1ppp/8/4p3/6Pq/5P2/PPPPP2P/RNBQKBNR w KQkq - 1 3'}
+ ];
+ for (var i = 0; i < positions.length; i++) {
+ passed = true;
+ error_message = "";
+ for (var j = 0; j < positions[i].moves.length; j++) {
+ if (chess.move(positions[i].moves[j]) === null) {
+ error_message = "move() did not accept " + positions[i].moves[j] + " : ";
+ break;
+ }
+ }
+ var s = 'PGN Test #' + i + ': ' + error_message;
+ chess.info.apply(null, positions[i].info);
+ var pgn = chess.pgn({max_width:positions[i].max_width, newline_char:positions[i].newline_char});
+ var fen = chess.fen();
+ passed = pgn === positions[i].pgn && fen === positions[i].fen;
+ s += (passed) ? 'PASSED!' : 'FAILED!';
+ log(s);
+ chess.reset();
+ }
+ var finish = new Date;
+ var diff = (finish-start) / 1000;
+ log('--> PGN Time: ' + diff + ' secs');
+ log('');
+}
+
function make_move_tests() {
var chess = new Chess();
var start = new Date;
@@ -416,6 +478,7 @@ function run_unit_tests() {
algebraic_notation_tests();
get_put_remove_tests();
fen_tests();
+ pgn_tests();
make_move_tests();
var finish = new Date;

0 comments on commit 84991c9

Please sign in to comment.