chesscademy 0.0.5 → 0.0.6

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ed82b82439c91c18a4dfc6d86cacb9662d95149a
4
- data.tar.gz: d021f35399561f1a98ae8f8ad69fdaa5f53eeea6
3
+ metadata.gz: 14b1be76e42689448ecc19d01af85f0e6fb518b8
4
+ data.tar.gz: 419ab22913890a15071ea9b7a7629bc1cde110fb
5
5
  SHA512:
6
- metadata.gz: cceb071a34aa59b0be26c9715cdc0a6420eab7020d95a4e38ac337e497c5c3a0fe867bfb41117c937686a5b0daddfac12ac34252fe3e6c36f038e0b572e484ee
7
- data.tar.gz: 20f39929c1703f373cd43b4db2730eaf1ea8385fe9ef711c037a3dd1249835b8c8b3ac571ddddde89eac44e79abcdc5ab291b6d2aa7591a6d49b757fc4cbceba
6
+ metadata.gz: a1a6b0825d52e219d36a7ef1d89b68c8ed41f59bcdb25106e98ac865be1e13b5d62a15d161e0e461e94e69b82c9508f521f167d46325f405b839b0adc60ea4fb
7
+ data.tar.gz: c11cab46873cfce4bdb67669bf396d02902665dede7cf149e2e76cf5b2ddf48c34f066dd7d3acfff76e329b8e2482624d8bc0ae8175fcfd464a6aabb5a439323
data/Gemfile CHANGED
@@ -1,4 +1,4 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
- # Specify your gem's dependencies in chesscademyA.gemspec
3
+ # Specify your gem's dependencies in nprogress-rails.gemspec
4
4
  gemspec
@@ -1,4 +1,4 @@
1
- Copyright (c) 2014 Francis Hinson
1
+ Copyright (c) 2013 Carlos Alexandro Becker
2
2
 
3
3
  MIT License
4
4
 
data/README.md CHANGED
@@ -6,7 +6,7 @@ TODO: Write a gem description
6
6
 
7
7
  Add this line to your application's Gemfile:
8
8
 
9
- gem 'chesscademyA'
9
+ gem 'chesscademy'
10
10
 
11
11
  And then execute:
12
12
 
@@ -14,7 +14,7 @@ And then execute:
14
14
 
15
15
  Or install it yourself as:
16
16
 
17
- $ gem install chesscademyA
17
+ $ gem install chesscademy
18
18
 
19
19
  ## Usage
20
20
 
data/Rakefile CHANGED
@@ -1,2 +1 @@
1
1
  require "bundler/gem_tasks"
2
-
@@ -0,0 +1,22 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = 'chesscademy'
7
+ spec.version = '0.0.6'
8
+ spec.authors = ['Francis Hinson']
9
+ spec.email = ['francis@chesscademy.com']
10
+ spec.description = %q{Chesscademy chess engine assets.}
11
+ spec.summary = %q{}
12
+ spec.homepage = 'https://github.com/Chesscademy'
13
+ spec.license = 'MIT'
14
+
15
+ spec.files = `git ls-files`.split($/)
16
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
17
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
18
+ spec.require_paths = ['lib']
19
+
20
+ spec.add_development_dependency 'bundler', '~> 1.3'
21
+ spec.add_development_dependency 'rake'
22
+ end
@@ -1,4 +1,4 @@
1
- module ChesscademyA
1
+ module Chesscademygem
2
2
  class Engine < ::Rails::Engine
3
3
  end
4
4
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: chesscademy
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.5
4
+ version: 0.0.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Francis Hinson
@@ -38,30 +38,21 @@ dependencies:
38
38
  - - ">="
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0'
41
- description: ''
41
+ description: Chesscademy chess engine assets.
42
42
  email:
43
- - francis@orchive.com
43
+ - francis@chesscademy.com
44
44
  executables: []
45
45
  extensions: []
46
46
  extra_rdoc_files: []
47
47
  files:
48
- - ".DS_Store"
49
48
  - ".gitignore"
50
49
  - Gemfile
51
50
  - LICENSE.txt
52
51
  - README.md
53
52
  - Rakefile
54
- - chesscademyA.gemspec
55
- - lib/.DS_Store
56
- - lib/chesscademyA.rb
57
- - lib/chesscademyA/.DS_Store
58
- - lib/chesscademyA/version.rb
59
- - vendor/.DS_Store
60
- - vendor/assets/.DS_Store
61
- - vendor/assets/javascripts/.DS_Store
62
- - vendor/assets/javascripts/chess.js
63
- - vendor/assets/javascripts/chessboard.js
64
- homepage: ''
53
+ - chesscademygem.gemspec
54
+ - lib/chesscademygem.rb
55
+ homepage: https://github.com/Chesscademy
65
56
  licenses:
66
57
  - MIT
67
58
  metadata: {}
@@ -84,5 +75,5 @@ rubyforge_project:
84
75
  rubygems_version: 2.2.0
85
76
  signing_key:
86
77
  specification_version: 4
87
- summary: Chesscademy chess engine assets.
78
+ summary: ''
88
79
  test_files: []
data/.DS_Store DELETED
Binary file
@@ -1,22 +0,0 @@
1
- # coding: utf-8
2
- lib = File.expand_path('../lib', __FILE__)
3
- $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
-
5
- Gem::Specification.new do |spec|
6
- spec.name = "chesscademy"
7
- spec.version = "0.0.5"
8
- spec.authors = ["Francis Hinson"]
9
- spec.email = ["francis@orchive.com"]
10
- spec.summary = %q{Chesscademy chess engine assets.}
11
- spec.description = %q{}
12
- spec.homepage = ""
13
- spec.license = "MIT"
14
-
15
- spec.files = `git ls-files`.split($/)
16
- spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
17
- spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
18
- spec.require_paths = ["lib"]
19
-
20
- spec.add_development_dependency "bundler", "~> 1.3"
21
- spec.add_development_dependency "rake"
22
- end
Binary file
Binary file
File without changes
Binary file
Binary file
@@ -1,1646 +0,0 @@
1
- // downloaded from https://github.com/jhlywa/chess.js/blob/master/chess.js
2
- // on 27 July 2013
3
- // commit: eed8f8a3b96d99fcd570b7ced105e8415409a800
4
-
5
- 'use strict';
6
-
7
- /*
8
- * Copyright (c) 2011, Jeff Hlywa (jhlywa@gmail.com)
9
- * All rights reserved.
10
- *
11
- * Redistribution and use in source and binary forms, with or without
12
- * modification, are permitted provided that the following conditions are met:
13
- *
14
- * 1. Redistributions of source code must retain the above copyright notice,
15
- * this list of conditions and the following disclaimer.
16
- * 2. Redistributions in binary form must reproduce the above copyright notice,
17
- * this list of conditions and the following disclaimer in the documentation
18
- * and/or other materials provided with the distribution.
19
- *
20
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
24
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30
- * POSSIBILITY OF SUCH DAMAGE.
31
- *
32
- *----------------------------------------------------------------------------*/
33
-
34
- window['Chess'] = window['Chess'] || function(fen) {
35
- //var Chess = function(fen) {
36
-
37
- /* jshint indent: false */
38
-
39
- var BLACK = 'b';
40
- var WHITE = 'w';
41
-
42
- var EMPTY = -1;
43
-
44
- var PAWN = 'p';
45
- var KNIGHT = 'n';
46
- var BISHOP = 'b';
47
- var ROOK = 'r';
48
- var QUEEN = 'q';
49
- var KING = 'k';
50
-
51
- var SYMBOLS = 'pnbrqkPNBRQK';
52
-
53
- var DEFAULT_POSITION = 'rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1';
54
-
55
- var POSSIBLE_RESULTS = ['1-0', '0-1', '1/2-1/2', '*'];
56
-
57
- var PAWN_OFFSETS = {
58
- b: [16, 32, 17, 15],
59
- w: [-16, -32, -17, -15]
60
- };
61
-
62
- var PIECE_OFFSETS = {
63
- n: [-18, -33, -31, -14, 18, 33, 31, 14],
64
- b: [-17, -15, 17, 15],
65
- r: [-16, 1, 16, -1],
66
- q: [-17, -16, -15, 1, 17, 16, 15, -1],
67
- k: [-17, -16, -15, 1, 17, 16, 15, -1]
68
- };
69
-
70
- var ATTACKS = [
71
- 20, 0, 0, 0, 0, 0, 0, 24, 0, 0, 0, 0, 0, 0,20, 0,
72
- 0,20, 0, 0, 0, 0, 0, 24, 0, 0, 0, 0, 0,20, 0, 0,
73
- 0, 0,20, 0, 0, 0, 0, 24, 0, 0, 0, 0,20, 0, 0, 0,
74
- 0, 0, 0,20, 0, 0, 0, 24, 0, 0, 0,20, 0, 0, 0, 0,
75
- 0, 0, 0, 0,20, 0, 0, 24, 0, 0,20, 0, 0, 0, 0, 0,
76
- 0, 0, 0, 0, 0,20, 2, 24, 2,20, 0, 0, 0, 0, 0, 0,
77
- 0, 0, 0, 0, 0, 2,53, 56, 53, 2, 0, 0, 0, 0, 0, 0,
78
- 24,24,24,24,24,24,56, 0, 56,24,24,24,24,24,24, 0,
79
- 0, 0, 0, 0, 0, 2,53, 56, 53, 2, 0, 0, 0, 0, 0, 0,
80
- 0, 0, 0, 0, 0,20, 2, 24, 2,20, 0, 0, 0, 0, 0, 0,
81
- 0, 0, 0, 0,20, 0, 0, 24, 0, 0,20, 0, 0, 0, 0, 0,
82
- 0, 0, 0,20, 0, 0, 0, 24, 0, 0, 0,20, 0, 0, 0, 0,
83
- 0, 0,20, 0, 0, 0, 0, 24, 0, 0, 0, 0,20, 0, 0, 0,
84
- 0,20, 0, 0, 0, 0, 0, 24, 0, 0, 0, 0, 0,20, 0, 0,
85
- 20, 0, 0, 0, 0, 0, 0, 24, 0, 0, 0, 0, 0, 0,20
86
- ];
87
-
88
- var RAYS = [
89
- 17, 0, 0, 0, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 15, 0,
90
- 0, 17, 0, 0, 0, 0, 0, 16, 0, 0, 0, 0, 0, 15, 0, 0,
91
- 0, 0, 17, 0, 0, 0, 0, 16, 0, 0, 0, 0, 15, 0, 0, 0,
92
- 0, 0, 0, 17, 0, 0, 0, 16, 0, 0, 0, 15, 0, 0, 0, 0,
93
- 0, 0, 0, 0, 17, 0, 0, 16, 0, 0, 15, 0, 0, 0, 0, 0,
94
- 0, 0, 0, 0, 0, 17, 0, 16, 0, 15, 0, 0, 0, 0, 0, 0,
95
- 0, 0, 0, 0, 0, 0, 17, 16, 15, 0, 0, 0, 0, 0, 0, 0,
96
- 1, 1, 1, 1, 1, 1, 1, 0, -1, -1, -1,-1, -1, -1, -1, 0,
97
- 0, 0, 0, 0, 0, 0,-15,-16,-17, 0, 0, 0, 0, 0, 0, 0,
98
- 0, 0, 0, 0, 0,-15, 0,-16, 0,-17, 0, 0, 0, 0, 0, 0,
99
- 0, 0, 0, 0,-15, 0, 0,-16, 0, 0,-17, 0, 0, 0, 0, 0,
100
- 0, 0, 0,-15, 0, 0, 0,-16, 0, 0, 0,-17, 0, 0, 0, 0,
101
- 0, 0,-15, 0, 0, 0, 0,-16, 0, 0, 0, 0,-17, 0, 0, 0,
102
- 0,-15, 0, 0, 0, 0, 0,-16, 0, 0, 0, 0, 0,-17, 0, 0,
103
- -15, 0, 0, 0, 0, 0, 0,-16, 0, 0, 0, 0, 0, 0,-17
104
- ];
105
-
106
- var SHIFTS = { p: 0, n: 1, b: 2, r: 3, q: 4, k: 5 };
107
-
108
- var FLAGS = {
109
- NORMAL: 'n',
110
- CAPTURE: 'c',
111
- BIG_PAWN: 'b',
112
- EP_CAPTURE: 'e',
113
- PROMOTION: 'p',
114
- KSIDE_CASTLE: 'k',
115
- QSIDE_CASTLE: 'q'
116
- };
117
-
118
- var BITS = {
119
- NORMAL: 1,
120
- CAPTURE: 2,
121
- BIG_PAWN: 4,
122
- EP_CAPTURE: 8,
123
- PROMOTION: 16,
124
- KSIDE_CASTLE: 32,
125
- QSIDE_CASTLE: 64
126
- };
127
-
128
- var RANK_1 = 7;
129
- var RANK_2 = 6;
130
- var RANK_3 = 5;
131
- var RANK_4 = 4;
132
- var RANK_5 = 3;
133
- var RANK_6 = 2;
134
- var RANK_7 = 1;
135
- var RANK_8 = 0;
136
-
137
- var SQUARES = {
138
- a8: 0, b8: 1, c8: 2, d8: 3, e8: 4, f8: 5, g8: 6, h8: 7,
139
- a7: 16, b7: 17, c7: 18, d7: 19, e7: 20, f7: 21, g7: 22, h7: 23,
140
- a6: 32, b6: 33, c6: 34, d6: 35, e6: 36, f6: 37, g6: 38, h6: 39,
141
- a5: 48, b5: 49, c5: 50, d5: 51, e5: 52, f5: 53, g5: 54, h5: 55,
142
- a4: 64, b4: 65, c4: 66, d4: 67, e4: 68, f4: 69, g4: 70, h4: 71,
143
- a3: 80, b3: 81, c3: 82, d3: 83, e3: 84, f3: 85, g3: 86, h3: 87,
144
- a2: 96, b2: 97, c2: 98, d2: 99, e2: 100, f2: 101, g2: 102, h2: 103,
145
- a1: 112, b1: 113, c1: 114, d1: 115, e1: 116, f1: 117, g1: 118, h1: 119
146
- };
147
-
148
- var ROOKS = {
149
- w: [{square: SQUARES.a1, flag: BITS.QSIDE_CASTLE},
150
- {square: SQUARES.h1, flag: BITS.KSIDE_CASTLE}],
151
- b: [{square: SQUARES.a8, flag: BITS.QSIDE_CASTLE},
152
- {square: SQUARES.h8, flag: BITS.KSIDE_CASTLE}]
153
- };
154
-
155
- var board = new Array(128);
156
- var kings = {w: EMPTY, b: EMPTY};
157
- var turn = WHITE;
158
- var castling = {w: 0, b: 0};
159
- var ep_square = EMPTY;
160
- var half_moves = 0;
161
- var move_number = 1;
162
- var history = [];
163
- var header = {};
164
-
165
- /* if the user passes in a fen string, load it, else default to
166
- * starting position
167
- */
168
- if (typeof fen === 'undefined') {
169
- load(DEFAULT_POSITION);
170
- } else {
171
- load(fen);
172
- }
173
-
174
- function clear() {
175
- board = new Array(128);
176
- kings = {w: EMPTY, b: EMPTY};
177
- turn = WHITE;
178
- castling = {w: 0, b: 0};
179
- ep_square = EMPTY;
180
- half_moves = 0;
181
- move_number = 1;
182
- history = [];
183
- header = {};
184
- update_setup(generate_fen());
185
- }
186
-
187
- function reset() {
188
- load(DEFAULT_POSITION);
189
- }
190
-
191
- function load(fen) {
192
- var tokens = fen.split(/\s+/);
193
- var position = tokens[0];
194
- var square = 0;
195
- var valid = SYMBOLS + '12345678/';
196
-
197
- if (!validate_fen(fen).valid) {
198
- return false;
199
- }
200
-
201
- clear();
202
-
203
- for (var i = 0; i < position.length; i++) {
204
- var piece = position.charAt(i);
205
-
206
- if (piece === '/') {
207
- square += 8;
208
- } else if (is_digit(piece)) {
209
- square += parseInt(piece, 10);
210
- } else {
211
- var color = (piece < 'a') ? WHITE : BLACK;
212
- put({type: piece.toLowerCase(), color: color}, algebraic(square));
213
- square++;
214
- }
215
- }
216
-
217
- turn = tokens[1];
218
-
219
- if (tokens[2].indexOf('K') > -1) {
220
- castling.w |= BITS.KSIDE_CASTLE;
221
- }
222
- if (tokens[2].indexOf('Q') > -1) {
223
- castling.w |= BITS.QSIDE_CASTLE;
224
- }
225
- if (tokens[2].indexOf('k') > -1) {
226
- castling.b |= BITS.KSIDE_CASTLE;
227
- }
228
- if (tokens[2].indexOf('q') > -1) {
229
- castling.b |= BITS.QSIDE_CASTLE;
230
- }
231
-
232
- ep_square = (tokens[3] === '-') ? EMPTY : SQUARES[tokens[3]];
233
- half_moves = parseInt(tokens[4], 10);
234
- move_number = parseInt(tokens[5], 10);
235
-
236
- update_setup(generate_fen());
237
-
238
- return true;
239
- }
240
-
241
- function validate_fen(fen) {
242
- var errors = {
243
- 0: 'No errors.',
244
- 1: 'FEN string must contain six space-delimited fields.',
245
- 2: '6th field (move number) must be a positive integer.',
246
- 3: '5th field (half move counter) must be a non-negative integer.',
247
- 4: '4th field (en-passant square) is invalid.',
248
- 5: '3rd field (castling availability) is invalid.',
249
- 6: '2nd field (side to move) is invalid.',
250
- 7: '1st field (piece positions) does not contain 8 \'/\'-delimited rows.',
251
- 8: '1st field (piece positions) is invalid [consecutive numbers].',
252
- 9: '1st field (piece positions) is invalid [invalid piece].',
253
- 10: '1st field (piece positions) is invalid [row too large].',
254
- };
255
-
256
- /* 1st criterion: 6 space-seperated fields? */
257
- var tokens = fen.split(/\s+/);
258
- if (tokens.length !== 6) {
259
- return {valid: false, error_number: 1, error: errors[1]};
260
- }
261
-
262
- /* 2nd criterion: move number field is a integer value > 0? */
263
- if (isNaN(tokens[5]) || (parseInt(tokens[5], 10) <= 0)) {
264
- return {valid: false, error_number: 2, error: errors[2]};
265
- }
266
-
267
- /* 3rd criterion: half move counter is an integer >= 0? */
268
- if (isNaN(tokens[4]) || (parseInt(tokens[4], 10) < 0)) {
269
- return {valid: false, error_number: 3, error: errors[3]};
270
- }
271
-
272
- /* 4th criterion: 4th field is a valid e.p.-string? */
273
- if (!/^(-|[abcdefgh][36])$/.test(tokens[3])) {
274
- return {valid: false, error_number: 4, error: errors[4]};
275
- }
276
-
277
- /* 5th criterion: 3th field is a valid castle-string? */
278
- if( !/^(KQ?k?q?|Qk?q?|kq?|q|-)$/.test(tokens[2])) {
279
- return {valid: false, error_number: 5, error: errors[5]};
280
- }
281
-
282
- /* 6th criterion: 2nd field is "w" (white) or "b" (black)? */
283
- if (!/^(w|b)$/.test(tokens[1])) {
284
- return {valid: false, error_number: 6, error: errors[6]};
285
- }
286
-
287
- /* 7th criterion: 1st field contains 8 rows? */
288
- var rows = tokens[0].split('/');
289
- if (rows.length !== 8) {
290
- return {valid: false, error_number: 7, error: errors[7]};
291
- }
292
-
293
- /* 8th criterion: every row is valid? */
294
- for (var i = 0; i < rows.length; i++) {
295
- /* check for right sum of fields AND not two numbers in succession */
296
- var sum_fields = 0;
297
- var previous_was_number = false;
298
-
299
- for (var k = 0; k < rows[i].length; k++) {
300
- if (!isNaN(rows[i][k])) {
301
- if (previous_was_number) {
302
- return {valid: false, error_number: 8, error: errors[8]};
303
- }
304
- sum_fields += parseInt(rows[i][k], 10);
305
- previous_was_number = true;
306
- } else {
307
- if (!/^[prnbqkPRNBQK]$/.test(rows[i][k])) {
308
- return {valid: false, error_number: 9, error: errors[9]};
309
- }
310
- sum_fields += 1;
311
- previous_was_number = false;
312
- }
313
- }
314
- if (sum_fields !== 8) {
315
- return {valid: false, error_number: 10, error: errors[10]};
316
- }
317
- }
318
-
319
- /* everything's okay! */
320
- return {valid: true, error_number: 0, error: errors[0]};
321
- }
322
-
323
- function generate_fen() {
324
- var empty = 0;
325
- var fen = '';
326
-
327
- for (var i = SQUARES.a8; i <= SQUARES.h1; i++) {
328
- if (board[i] == null) {
329
- empty++;
330
- } else {
331
- if (empty > 0) {
332
- fen += empty;
333
- empty = 0;
334
- }
335
- var color = board[i].color;
336
- var piece = board[i].type;
337
-
338
- fen += (color === WHITE) ?
339
- piece.toUpperCase() : piece.toLowerCase();
340
- }
341
-
342
- if ((i + 1) & 0x88) {
343
- if (empty > 0) {
344
- fen += empty;
345
- }
346
-
347
- if (i !== SQUARES.h1) {
348
- fen += '/';
349
- }
350
-
351
- empty = 0;
352
- i += 8;
353
- }
354
- }
355
-
356
- var cflags = '';
357
- if (castling[WHITE] & BITS.KSIDE_CASTLE) { cflags += 'K'; }
358
- if (castling[WHITE] & BITS.QSIDE_CASTLE) { cflags += 'Q'; }
359
- if (castling[BLACK] & BITS.KSIDE_CASTLE) { cflags += 'k'; }
360
- if (castling[BLACK] & BITS.QSIDE_CASTLE) { cflags += 'q'; }
361
-
362
- /* do we have an empty castling flag? */
363
- cflags = cflags || '-';
364
- var epflags = (ep_square === EMPTY) ? '-' : algebraic(ep_square);
365
-
366
- return [fen, turn, cflags, epflags, half_moves, move_number].join(' ');
367
- }
368
-
369
- function set_header(args) {
370
- for (var i = 0; i < args.length; i += 2) {
371
- if (typeof args[i] === 'string' &&
372
- typeof args[i + 1] === 'string') {
373
- header[args[i]] = args[i + 1];
374
- }
375
- }
376
- return header;
377
- }
378
-
379
- /* called when the initial board setup is changed with put() or remove().
380
- * modifies the SetUp and FEN properties of the header object. if the FEN is
381
- * equal to the default position, the SetUp and FEN are deleted
382
- * the setup is only updated if history.length is zero, ie moves haven't been
383
- * made.
384
- */
385
- function update_setup(fen) {
386
- if (history.length > 0) return;
387
-
388
- if (fen !== DEFAULT_POSITION) {
389
- //header['SetUp'] = fen;
390
- //header['FEN'] = '1';
391
- } else {
392
- delete header['SetUp'];
393
- delete header['FEN'];
394
- }
395
- }
396
-
397
- function get(square) {
398
- var piece = board[SQUARES[square]];
399
- return (piece) ? {type: piece.type, color: piece.color} : null;
400
- }
401
-
402
- function put(piece, square) {
403
- /* check for valid piece object */
404
- if (!('type' in piece && 'color' in piece)) {
405
- return false;
406
- }
407
-
408
- /* check for piece */
409
- if (SYMBOLS.indexOf(piece.type.toLowerCase()) === -1) {
410
- return false;
411
- }
412
-
413
- /* check for valid square */
414
- if (!(square in SQUARES)) {
415
- return false;
416
- }
417
-
418
- var sq = SQUARES[square];
419
- board[sq] = {type: piece.type, color: piece.color};
420
- if (piece.type === KING) {
421
- kings[piece.color] = sq;
422
- }
423
-
424
- update_setup(generate_fen());
425
-
426
- return true;
427
- }
428
-
429
- function remove(square) {
430
- var piece = get(square);
431
- board[SQUARES[square]] = null;
432
- if (piece && piece.type === KING) {
433
- kings[piece.color] = EMPTY;
434
- }
435
-
436
- update_setup(generate_fen());
437
-
438
- return piece;
439
- }
440
-
441
- function build_move(board, from, to, flags, promotion) {
442
- var move = {
443
- color: turn,
444
- from: from,
445
- to: to,
446
- flags: flags,
447
- piece: board[from].type
448
- };
449
-
450
- if (promotion) {
451
- move.flags |= BITS.PROMOTION;
452
- move.promotion = promotion;
453
- }
454
-
455
- if (board[to]) {
456
- move.captured = board[to].type;
457
- } else if (flags & BITS.EP_CAPTURE) {
458
- move.captured = PAWN;
459
- }
460
- return move;
461
- }
462
-
463
- function generate_moves(options) {
464
- function add_move(board, moves, from, to, flags) {
465
- /* if pawn promotion */
466
- if (board[from].type === PAWN &&
467
- (rank(to) === RANK_8 || rank(to) === RANK_1)) {
468
- var pieces = [QUEEN, ROOK, BISHOP, KNIGHT];
469
- for (var i = 0, len = pieces.length; i < len; i++) {
470
- moves.push(build_move(board, from, to, flags, pieces[i]));
471
- }
472
- } else {
473
- moves.push(build_move(board, from, to, flags));
474
- }
475
- }
476
-
477
- var moves = [];
478
- var us = turn;
479
- var them = swap_color(us);
480
- var second_rank = {b: RANK_7, w: RANK_2};
481
-
482
- var first_sq = SQUARES.a8;
483
- var last_sq = SQUARES.h1;
484
- var single_square = false;
485
-
486
- /* do we want legal moves? */
487
- var legal = (typeof options !== 'undefined' && 'legal' in options) ?
488
- options.legal : true;
489
-
490
- /* are we generating moves for a single square? */
491
- if (typeof options !== 'undefined' && 'square' in options) {
492
- if (options.square in SQUARES) {
493
- first_sq = last_sq = SQUARES[options.square];
494
- single_square = true;
495
- } else {
496
- /* invalid square */
497
- return [];
498
- }
499
- }
500
-
501
- for (var i = first_sq; i <= last_sq; i++) {
502
- /* did we run off the end of the board */
503
- if (i & 0x88) { i += 7; continue; }
504
-
505
- var piece = board[i];
506
- if (piece == null || piece.color !== us) {
507
- continue;
508
- }
509
-
510
- if (piece.type === PAWN) {
511
- /* single square, non-capturing */
512
- var square = i + PAWN_OFFSETS[us][0];
513
- if (board[square] == null) {
514
- add_move(board, moves, i, square, BITS.NORMAL);
515
-
516
- /* double square */
517
- var square = i + PAWN_OFFSETS[us][1];
518
- if (second_rank[us] === rank(i) && board[square] == null) {
519
- add_move(board, moves, i, square, BITS.BIG_PAWN);
520
- }
521
- }
522
-
523
- /* pawn captures */
524
- for (j = 2; j < 4; j++) {
525
- var square = i + PAWN_OFFSETS[us][j];
526
- if (square & 0x88) continue;
527
-
528
- if (board[square] != null &&
529
- board[square].color === them) {
530
- add_move(board, moves, i, square, BITS.CAPTURE);
531
- } else if (square === ep_square) {
532
- add_move(board, moves, i, ep_square, BITS.EP_CAPTURE);
533
- }
534
- }
535
- } else {
536
- for (var j = 0, len = PIECE_OFFSETS[piece.type].length; j < len; j++) {
537
- var offset = PIECE_OFFSETS[piece.type][j];
538
- var square = i;
539
-
540
- while (true) {
541
- square += offset;
542
- if (square & 0x88) break;
543
-
544
- if (board[square] == null) {
545
- add_move(board, moves, i, square, BITS.NORMAL);
546
- } else {
547
- if (board[square].color === us) break;
548
- add_move(board, moves, i, square, BITS.CAPTURE);
549
- break;
550
- }
551
-
552
- /* break, if knight or king */
553
- if (piece.type === 'n' || piece.type === 'k') break;
554
- }
555
- }
556
- }
557
- }
558
-
559
- /* check for castling if: a) we're generating all moves, or b) we're doing
560
- * single square move generation on the king's square
561
- */
562
- if ((!single_square) || last_sq === kings[us]) {
563
- /* king-side castling */
564
- if (castling[us] & BITS.KSIDE_CASTLE) {
565
- var castling_from = kings[us];
566
- var castling_to = castling_from + 2;
567
-
568
- if (board[castling_from + 1] == null &&
569
- board[castling_to] == null &&
570
- !attacked(them, kings[us]) &&
571
- !attacked(them, castling_from + 1) &&
572
- !attacked(them, castling_to)) {
573
- add_move(board, moves, kings[us] , castling_to,
574
- BITS.KSIDE_CASTLE);
575
- }
576
- }
577
-
578
- /* queen-side castling */
579
- if (castling[us] & BITS.QSIDE_CASTLE) {
580
- var castling_from = kings[us];
581
- var castling_to = castling_from - 2;
582
-
583
- if (board[castling_from - 1] == null &&
584
- board[castling_from - 2] == null &&
585
- board[castling_from - 3] == null &&
586
- !attacked(them, kings[us]) &&
587
- !attacked(them, castling_from - 1) &&
588
- !attacked(them, castling_to)) {
589
- add_move(board, moves, kings[us], castling_to,
590
- BITS.QSIDE_CASTLE);
591
- }
592
- }
593
- }
594
-
595
- /* return all pseudo-legal moves (this includes moves that allow the king
596
- * to be captured)
597
- */
598
- if (!legal) {
599
- return moves;
600
- }
601
-
602
- /* filter out illegal moves */
603
- var legal_moves = [];
604
- for (var i = 0, len = moves.length; i < len; i++) {
605
- make_move(moves[i]);
606
- if (!king_attacked(us)) {
607
- legal_moves.push(moves[i]);
608
- }
609
- undo_move();
610
- }
611
-
612
- return legal_moves;
613
- }
614
-
615
- /* convert a move from 0x88 coordinates to Standard Algebraic Notation
616
- * (SAN)
617
- */
618
- function move_to_san(move) {
619
- var output = '';
620
-
621
- if (move.flags & BITS.KSIDE_CASTLE) {
622
- output = 'O-O';
623
- } else if (move.flags & BITS.QSIDE_CASTLE) {
624
- output = 'O-O-O';
625
- } else {
626
- var disambiguator = get_disambiguator(move);
627
-
628
- if (move.piece !== PAWN) {
629
- output += move.piece.toUpperCase() + disambiguator;
630
- }
631
-
632
- if (move.flags & (BITS.CAPTURE | BITS.EP_CAPTURE)) {
633
- if (move.piece === PAWN) {
634
- output += algebraic(move.from)[0];
635
- }
636
- output += 'x';
637
- }
638
-
639
- output += algebraic(move.to);
640
-
641
- if (move.flags & BITS.PROMOTION) {
642
- output += '=' + move.promotion.toUpperCase();
643
- }
644
- }
645
-
646
- make_move(move);
647
- if (in_check()) {
648
- if (in_checkmate()) {
649
- output += '#';
650
- } else {
651
- output += '+';
652
- }
653
- }
654
- undo_move();
655
-
656
- return output;
657
- }
658
-
659
- function attacked(color, square) {
660
- for (var i = SQUARES.a8; i <= SQUARES.h1; i++) {
661
- /* did we run off the end of the board */
662
- if (i & 0x88) { i += 7; continue; }
663
-
664
- /* if empty square or wrong color */
665
- if (board[i] == null || board[i].color !== color) continue;
666
-
667
- var piece = board[i];
668
- var difference = i - square;
669
- var index = difference + 119;
670
-
671
- if (ATTACKS[index] & (1 << SHIFTS[piece.type])) {
672
- if (piece.type === PAWN) {
673
- if (difference > 0) {
674
- if (piece.color === WHITE) return true;
675
- } else {
676
- if (piece.color === BLACK) return true;
677
- }
678
- continue;
679
- }
680
-
681
- /* if the piece is a knight or a king */
682
- if (piece.type === 'n' || piece.type === 'k') return true;
683
-
684
- var offset = RAYS[index];
685
- var j = i + offset;
686
-
687
- var blocked = false;
688
- while (j !== square) {
689
- if (board[j] != null) { blocked = true; break; }
690
- j += offset;
691
- }
692
-
693
- if (!blocked) return true;
694
- }
695
- }
696
-
697
- return false;
698
- }
699
-
700
- function king_attacked(color) {
701
- return attacked(swap_color(color), kings[color]);
702
- }
703
-
704
- function in_check() {
705
- return king_attacked(turn);
706
- }
707
-
708
- function in_checkmate() {
709
- return in_check() && generate_moves().length === 0;
710
- }
711
-
712
- function in_stalemate() {
713
- return !in_check() && generate_moves().length === 0;
714
- }
715
-
716
- function insufficient_material() {
717
- var pieces = {};
718
- var bishops = [];
719
- var num_pieces = 0;
720
- var sq_color = 0;
721
-
722
- for (var i = SQUARES.a8; i<= SQUARES.h1; i++) {
723
- sq_color = (sq_color + 1) % 2;
724
- if (i & 0x88) { i += 7; continue; }
725
-
726
- var piece = board[i];
727
- if (piece) {
728
- pieces[piece.type] = (piece.type in pieces) ?
729
- pieces[piece.type] + 1 : 1;
730
- if (piece.type === BISHOP) {
731
- bishops.push(sq_color);
732
- }
733
- num_pieces++;
734
- }
735
- }
736
-
737
- /* k vs. k */
738
- if (num_pieces === 2) { return true; }
739
-
740
- /* k vs. kn .... or .... k vs. kb */
741
- else if (num_pieces === 3 && (pieces[BISHOP] === 1 ||
742
- pieces[KNIGHT] === 1)) { return true; }
743
-
744
- /* kb vs. kb where any number of bishops are all on the same color */
745
- else if (num_pieces === pieces[BISHOP] + 2) {
746
- var sum = 0;
747
- var len = bishops.length;
748
- for (var i = 0; i < len; i++) {
749
- sum += bishops[i];
750
- }
751
- if (sum === 0 || sum === len) { return true; }
752
- }
753
-
754
- return false;
755
- }
756
-
757
- function in_threefold_repetition() {
758
- /* TODO: while this function is fine for casual use, a better
759
- * implementation would use a Zobrist key (instead of FEN). the
760
- * Zobrist key would be maintained in the make_move/undo_move functions,
761
- * avoiding the costly that we do below.
762
- */
763
- var moves = [];
764
- var positions = {};
765
- var repetition = false;
766
-
767
- while (true) {
768
- var move = undo_move();
769
- if (!move) break;
770
- moves.push(move);
771
- }
772
-
773
- while (true) {
774
- /* remove the last two fields in the FEN string, they're not needed
775
- * when checking for draw by rep */
776
- var fen = generate_fen().split(' ').slice(0,4).join(' ');
777
-
778
- /* has the position occurred three or move times */
779
- positions[fen] = (fen in positions) ? positions[fen] + 1 : 1;
780
- if (positions[fen] >= 3) {
781
- repetition = true;
782
- }
783
-
784
- if (!moves.length) {
785
- break;
786
- }
787
- make_move(moves.pop());
788
- }
789
-
790
- return repetition;
791
- }
792
-
793
- function push(move) {
794
- history.push({
795
- move: move,
796
- kings: {b: kings.b, w: kings.w},
797
- turn: turn,
798
- castling: {b: castling.b, w: castling.w},
799
- ep_square: ep_square,
800
- half_moves: half_moves,
801
- move_number: move_number
802
- });
803
- }
804
-
805
- function make_move(move) {
806
- var us = turn;
807
- var them = swap_color(us);
808
- push(move);
809
-
810
- board[move.to] = board[move.from];
811
- board[move.from] = null;
812
-
813
- /* if ep capture, remove the captured pawn */
814
- if (move.flags & BITS.EP_CAPTURE) {
815
- if (turn === BLACK) {
816
- board[move.to - 16] = null;
817
- } else {
818
- board[move.to + 16] = null;
819
- }
820
- }
821
-
822
- /* if pawn promotion, replace with new piece */
823
- if (move.flags & BITS.PROMOTION) {
824
- board[move.to] = {type: move.promotion, color: us};
825
- }
826
-
827
- /* if we moved the king */
828
- if (board[move.to].type === KING) {
829
- kings[board[move.to].color] = move.to;
830
-
831
- /* if we castled, move the rook next to the king */
832
- if (move.flags & BITS.KSIDE_CASTLE) {
833
- var castling_to = move.to - 1;
834
- var castling_from = move.to + 1;
835
- board[castling_to] = board[castling_from];
836
- board[castling_from] = null;
837
- } else if (move.flags & BITS.QSIDE_CASTLE) {
838
- var castling_to = move.to + 1;
839
- var castling_from = move.to - 2;
840
- board[castling_to] = board[castling_from];
841
- board[castling_from] = null;
842
- }
843
-
844
- /* turn off castling */
845
- castling[us] = '';
846
- }
847
-
848
- /* turn off castling if we move a rook */
849
- if (castling[us]) {
850
- for (var i = 0, len = ROOKS[us].length; i < len; i++) {
851
- if (move.from === ROOKS[us][i].square &&
852
- castling[us] & ROOKS[us][i].flag) {
853
- castling[us] ^= ROOKS[us][i].flag;
854
- break;
855
- }
856
- }
857
- }
858
-
859
- /* turn off castling if we capture a rook */
860
- if (castling[them]) {
861
- for (var i = 0, len = ROOKS[them].length; i < len; i++) {
862
- if (move.to === ROOKS[them][i].square &&
863
- castling[them] & ROOKS[them][i].flag) {
864
- castling[them] ^= ROOKS[them][i].flag;
865
- break;
866
- }
867
- }
868
- }
869
-
870
- /* if big pawn move, update the en passant square */
871
- if (move.flags & BITS.BIG_PAWN) {
872
- if (turn === 'b') {
873
- ep_square = move.to - 16;
874
- } else {
875
- ep_square = move.to + 16;
876
- }
877
- } else {
878
- ep_square = EMPTY;
879
- }
880
-
881
- /* reset the 50 move counter if a pawn is moved or a piece is captured */
882
- if (move.piece === PAWN) {
883
- half_moves = 0;
884
- } else if (move.flags & (BITS.CAPTURE | BITS.EP_CAPTURE)) {
885
- half_moves = 0;
886
- } else {
887
- half_moves++;
888
- }
889
-
890
- if (turn === BLACK) {
891
- move_number++;
892
- }
893
- turn = swap_color(turn);
894
- }
895
-
896
- function undo_move() {
897
- var old = history.pop();
898
- if (old == null) { return null; }
899
-
900
- var move = old.move;
901
- kings = old.kings;
902
- turn = old.turn;
903
- castling = old.castling;
904
- ep_square = old.ep_square;
905
- half_moves = old.half_moves;
906
- move_number = old.move_number;
907
-
908
- var us = turn;
909
- var them = swap_color(turn);
910
-
911
- board[move.from] = board[move.to];
912
- board[move.from].type = move.piece; // to undo any promotions
913
- board[move.to] = null;
914
-
915
- if (move.flags & BITS.CAPTURE) {
916
- board[move.to] = {type: move.captured, color: them};
917
- } else if (move.flags & BITS.EP_CAPTURE) {
918
- var index;
919
- if (us === BLACK) {
920
- index = move.to - 16;
921
- } else {
922
- index = move.to + 16;
923
- }
924
- board[index] = {type: PAWN, color: them};
925
- }
926
-
927
-
928
- if (move.flags & (BITS.KSIDE_CASTLE | BITS.QSIDE_CASTLE)) {
929
- var castling_to, castling_from;
930
- if (move.flags & BITS.KSIDE_CASTLE) {
931
- castling_to = move.to + 1;
932
- castling_from = move.to - 1;
933
- } else if (move.flags & BITS.QSIDE_CASTLE) {
934
- castling_to = move.to - 2;
935
- castling_from = move.to + 1;
936
- }
937
-
938
- board[castling_to] = board[castling_from];
939
- board[castling_from] = null;
940
- }
941
-
942
- return move;
943
- }
944
-
945
- /* this function is used to uniquely identify ambiguous moves */
946
- function get_disambiguator(move) {
947
- var moves = generate_moves();
948
-
949
- var from = move.from;
950
- var to = move.to;
951
- var piece = move.piece;
952
-
953
- var ambiguities = 0;
954
- var same_rank = 0;
955
- var same_file = 0;
956
-
957
- for (var i = 0, len = moves.length; i < len; i++) {
958
- var ambig_from = moves[i].from;
959
- var ambig_to = moves[i].to;
960
- var ambig_piece = moves[i].piece;
961
-
962
- /* if a move of the same piece type ends on the same to square, we'll
963
- * need to add a disambiguator to the algebraic notation
964
- */
965
- if (piece === ambig_piece && from !== ambig_from && to === ambig_to) {
966
- ambiguities++;
967
-
968
- if (rank(from) === rank(ambig_from)) {
969
- same_rank++;
970
- }
971
-
972
- if (file(from) === file(ambig_from)) {
973
- same_file++;
974
- }
975
- }
976
- }
977
-
978
- if (ambiguities > 0) {
979
- /* if there exists a similar moving piece on the same rank and file as
980
- * the move in question, use the square as the disambiguator
981
- */
982
- if (same_rank > 0 && same_file > 0) {
983
- return algebraic(from);
984
- }
985
- /* if the moving piece rests on the same file, use the rank symbol as the
986
- * disambiguator
987
- */
988
- else if (same_file > 0) {
989
- return algebraic(from).charAt(1);
990
- }
991
- /* else use the file symbol */
992
- else {
993
- return algebraic(from).charAt(0);
994
- }
995
- }
996
-
997
- return '';
998
- }
999
-
1000
- function ascii() {
1001
- var s = ' +------------------------+\n';
1002
- for (var i = SQUARES.a8; i <= SQUARES.h1; i++) {
1003
- /* display the rank */
1004
- if (file(i) === 0) {
1005
- s += ' ' + '87654321'[rank(i)] + ' |';
1006
- }
1007
-
1008
- /* empty piece */
1009
- if (board[i] == null) {
1010
- s += ' . ';
1011
- } else {
1012
- var piece = board[i].type;
1013
- var color = board[i].color;
1014
- var symbol = (color === WHITE) ?
1015
- piece.toUpperCase() : piece.toLowerCase();
1016
- s += ' ' + symbol + ' ';
1017
- }
1018
-
1019
- if ((i + 1) & 0x88) {
1020
- s += '|\n';
1021
- i += 8;
1022
- }
1023
- }
1024
- s += ' +------------------------+\n';
1025
- s += ' a b c d e f g h\n';
1026
-
1027
- return s;
1028
- }
1029
-
1030
- /*****************************************************************************
1031
- * UTILITY FUNCTIONS
1032
- ****************************************************************************/
1033
- function rank(i) {
1034
- return i >> 4;
1035
- }
1036
-
1037
- function file(i) {
1038
- return i & 15;
1039
- }
1040
-
1041
- function algebraic(i){
1042
- var f = file(i), r = rank(i);
1043
- return 'abcdefgh'.substring(f,f+1) + '87654321'.substring(r,r+1);
1044
- }
1045
-
1046
- function swap_color(c) {
1047
- return c === WHITE ? BLACK : WHITE;
1048
- }
1049
-
1050
- function is_digit(c) {
1051
- return '0123456789'.indexOf(c) !== -1;
1052
- }
1053
-
1054
- /* pretty = external move object */
1055
- function make_pretty(ugly_move) {
1056
- var move = clone(ugly_move);
1057
- move.san = move_to_san(move);
1058
- move.to = algebraic(move.to);
1059
- move.from = algebraic(move.from);
1060
-
1061
- var flags = '';
1062
-
1063
- for (var flag in BITS) {
1064
- if (BITS[flag] & move.flags) {
1065
- flags += FLAGS[flag];
1066
- }
1067
- }
1068
- move.flags = flags;
1069
-
1070
- return move;
1071
- }
1072
-
1073
- function clone(obj) {
1074
- var dupe = (obj instanceof Array) ? [] : {};
1075
-
1076
- for (var property in obj) {
1077
- if (typeof property === 'object') {
1078
- dupe[property] = clone(obj[property]);
1079
- } else {
1080
- dupe[property] = obj[property];
1081
- }
1082
- }
1083
-
1084
- return dupe;
1085
- }
1086
-
1087
- function trim(str) {
1088
- return str.replace(/^\s+|\s+$/g, '');
1089
- }
1090
-
1091
- /*****************************************************************************
1092
- * DEBUGGING UTILITIES
1093
- ****************************************************************************/
1094
- function perft(depth) {
1095
- var moves = generate_moves({legal: false});
1096
- var nodes = 0;
1097
- var color = turn;
1098
-
1099
- for (var i = 0, len = moves.length; i < len; i++) {
1100
- make_move(moves[i]);
1101
- if (!king_attacked(color)) {
1102
- if (depth - 1 > 0) {
1103
- var child_nodes = perft(depth - 1);
1104
- nodes += child_nodes;
1105
- } else {
1106
- nodes++;
1107
- }
1108
- }
1109
- undo_move();
1110
- }
1111
-
1112
- return nodes;
1113
- }
1114
-
1115
- return {
1116
- /***************************************************************************
1117
- * PUBLIC CONSTANTS (is there a better way to do this?)
1118
- **************************************************************************/
1119
- WHITE: WHITE,
1120
- BLACK: BLACK,
1121
- PAWN: PAWN,
1122
- KNIGHT: KNIGHT,
1123
- BISHOP: BISHOP,
1124
- ROOK: ROOK,
1125
- QUEEN: QUEEN,
1126
- KING: KING,
1127
- SQUARES: (function() {
1128
- /* from the ECMA-262 spec (section 12.6.4):
1129
- * "The mechanics of enumerating the properties ... is
1130
- * implementation dependent"
1131
- * so: for (var sq in SQUARES) { keys.push(sq); } might not be
1132
- * ordered correctly
1133
- */
1134
- var keys = [];
1135
- for (var i = SQUARES.a8; i <= SQUARES.h1; i++) {
1136
- if (i & 0x88) { i += 7; continue; }
1137
- keys.push(algebraic(i));
1138
- }
1139
- return keys;
1140
- })(),
1141
- FLAGS: FLAGS,
1142
-
1143
- /***************************************************************************
1144
- * PUBLIC API
1145
- **************************************************************************/
1146
- load: function(fen) {
1147
- return load(fen);
1148
- },
1149
-
1150
- reset: function() {
1151
- return reset();
1152
- },
1153
-
1154
- moves: function(options) {
1155
- /* The internal representation of a chess move is in 0x88 format, and
1156
- * not meant to be human-readable. The code below converts the 0x88
1157
- * square coordinates to algebraic coordinates. It also prunes an
1158
- * unnecessary move keys resulting from a verbose call.
1159
- */
1160
-
1161
- var ugly_moves = generate_moves(options);
1162
- var moves = [];
1163
-
1164
- for (var i = 0, len = ugly_moves.length; i < len; i++) {
1165
-
1166
- /* does the user want a full move object (most likely not), or just
1167
- * SAN
1168
- */
1169
- if (typeof options !== 'undefined' && 'verbose' in options &&
1170
- options.verbose) {
1171
- moves.push(make_pretty(ugly_moves[i]));
1172
- } else {
1173
- moves.push(move_to_san(ugly_moves[i]));
1174
- }
1175
- }
1176
-
1177
- return moves;
1178
- },
1179
-
1180
- in_check: function() {
1181
- return in_check();
1182
- },
1183
-
1184
- in_checkmate: function() {
1185
- return in_checkmate();
1186
- },
1187
-
1188
- in_stalemate: function() {
1189
- return in_stalemate();
1190
- },
1191
-
1192
- in_draw: function() {
1193
- return half_moves >= 100 ||
1194
- in_stalemate() ||
1195
- insufficient_material() ||
1196
- in_threefold_repetition();
1197
- },
1198
-
1199
- insufficient_material: function() {
1200
- return insufficient_material();
1201
- },
1202
-
1203
- in_threefold_repetition: function() {
1204
- return in_threefold_repetition();
1205
- },
1206
-
1207
- game_over: function() {
1208
- return half_moves >= 100 ||
1209
- in_checkmate() ||
1210
- in_stalemate() ||
1211
- insufficient_material() ||
1212
- in_threefold_repetition();
1213
- },
1214
-
1215
- validate_fen: function(fen) {
1216
- return validate_fen(fen);
1217
- },
1218
-
1219
- fen: function() {
1220
- return generate_fen();
1221
- },
1222
-
1223
- pgn: function(options) {
1224
- /* using the specification from http://www.chessclub.com/help/PGN-spec
1225
- * example for html usage: .pgn({ max_width: 72, newline_char: "<br />" })
1226
- */
1227
- var newline = (typeof options === 'object' &&
1228
- typeof options.newline_char === 'string') ?
1229
- options.newline_char : '\n';
1230
- var max_width = (typeof options === 'object' &&
1231
- typeof options.max_width === 'number') ?
1232
- options.max_width : 0;
1233
- var result = [];
1234
- var header_exists = false;
1235
-
1236
- /* add the PGN header headerrmation */
1237
- for (var i in header) {
1238
- /* TODO: order of enumerated properties in header object is not
1239
- * guaranteed, see ECMA-262 spec (section 12.6.4)
1240
- */
1241
- result.push('[' + i + ' \"' + header[i] + '\"]' + newline);
1242
- header_exists = true;
1243
- }
1244
-
1245
- if (header_exists && history.length) {
1246
- result.push(newline);
1247
- }
1248
-
1249
- /* pop all of history onto reversed_history */
1250
- var reversed_history = [];
1251
- while (history.length > 0) {
1252
- reversed_history.push(undo_move());
1253
- }
1254
-
1255
- var moves = [];
1256
- var move_string = '';
1257
- var pgn_move_number = 1;
1258
-
1259
- /* build the list of moves. a move_string looks like: "3. e3 e6" */
1260
- while (reversed_history.length > 0) {
1261
- var move = reversed_history.pop();
1262
-
1263
- /* if the position started with black to move, start PGN with 1. ... */
1264
- if (pgn_move_number === 1 && move.color === 'b') {
1265
- move_string = '1. ...';
1266
- pgn_move_number++;
1267
- } else if (move.color === 'w') {
1268
- /* store the previous generated move_string if we have one */
1269
- if (move_string.length) {
1270
- moves.push(move_string);
1271
- }
1272
- move_string = pgn_move_number + '.';
1273
- pgn_move_number++;
1274
- }
1275
-
1276
- move_string = move_string + ' ' + move_to_san(move);
1277
- make_move(move);
1278
- }
1279
-
1280
- /* are there any other leftover moves? */
1281
- if (move_string.length) {
1282
- moves.push(move_string);
1283
- }
1284
-
1285
- /* is there a result? */
1286
- if (typeof header.Result !== 'undefined') {
1287
- moves.push(header.Result);
1288
- }
1289
-
1290
- /* history should be back to what is was before we started generating PGN,
1291
- * so join together moves
1292
- */
1293
- if (max_width === 0) {
1294
- return result.join('') + moves.join(' ');
1295
- }
1296
-
1297
- /* wrap the PGN output at max_width */
1298
- var current_width = 0;
1299
- for (var i = 0; i < moves.length; i++) {
1300
- /* if the current move will push past max_width */
1301
- if (current_width + moves[i].length > max_width && i !== 0) {
1302
-
1303
- /* don't end the line with whitespace */
1304
- if (result[result.length - 1] === ' ') {
1305
- result.pop();
1306
- }
1307
-
1308
- result.push(newline);
1309
- current_width = 0;
1310
- } else if (i !== 0) {
1311
- result.push(' ');
1312
- current_width++;
1313
- }
1314
- result.push(moves[i]);
1315
- current_width += moves[i].length;
1316
- }
1317
-
1318
- return result.join('');
1319
- },
1320
-
1321
- load_pgn: function(pgn, options) {
1322
- function mask(str) {
1323
- return str.replace(/\n/g, '\\n').replace(/\r/g, '\\r');
1324
- }
1325
-
1326
- /* convert a move from Standard Algebraic Notation (SAN) to 0x88
1327
- * coordinates
1328
- */
1329
- function move_from_san(move) {
1330
- var to, from, flags = BITS.NORMAL, promotion;
1331
- var parse = move.match(/^([NBKRQ])?([abcdefgh12345678][12345678]?)?(x)?([abcdefgh][12345678])(=?[NBRQ])?/);
1332
- if (move.slice(0, 5) === 'O-O-O') {
1333
- from = kings[turn];
1334
- to = from - 2;
1335
- flags = BITS.QSIDE_CASTLE;
1336
- } else if (move.slice(0, 3) === 'O-O') {
1337
- from = kings[turn];
1338
- to = from + 2;
1339
- flags = BITS.KSIDE_CASTLE;
1340
- } else if (parse && parse[1]) {
1341
- // regular moves
1342
- var piece = parse[1].toLowerCase();
1343
- if (parse[3]) {
1344
- // capture
1345
- flags = BITS.CAPTURE;
1346
- }
1347
- to = SQUARES[parse[4]];
1348
- for (var j = 0, len = PIECE_OFFSETS[piece].length; j < len; j++) {
1349
- var offset = PIECE_OFFSETS[piece][j];
1350
- var square = to;
1351
-
1352
- while (true) {
1353
- square += offset;
1354
- if (square & 0x88) break;
1355
-
1356
- var b = board[square];
1357
- if (b) {
1358
- if (b.color === turn && b.type === piece && (!parse[2] || algebraic(square).indexOf(parse[2]) >= 0)) {
1359
- from = square;
1360
- }
1361
- break;
1362
- }
1363
-
1364
- /* break, if knight or king */
1365
- if (piece === 'n' || piece === 'k') break;
1366
- }
1367
- }
1368
- } else if (parse) {
1369
- // pawn move
1370
- if (parse[3]) {
1371
- // capture
1372
- to = SQUARES[parse[4]];
1373
- for (var j = 2; j < 4; j++) {
1374
- var square = to - PAWN_OFFSETS[turn][j];
1375
- if (square & 0x88) continue;
1376
-
1377
- if (board[square] != null &&
1378
- board[square].color === turn &&
1379
- algebraic(square)[0] === parse[2]) {
1380
- from = square;
1381
- }
1382
- }
1383
- if (board[to]) {
1384
- flags = BITS.CAPTURE;
1385
- } else {
1386
- flags = BITS.EP_CAPTURE;
1387
- }
1388
- } else {
1389
- // normal move
1390
- to = SQUARES[move.slice(0,2)];
1391
- var c = to - PAWN_OFFSETS[turn][0],
1392
- b = board[c];
1393
- if (b && b.type === PAWN && b.color === turn) {
1394
- from = c;
1395
- } else {
1396
- c = to - PAWN_OFFSETS[turn][1];
1397
- b = board[c];
1398
- if (b && b.type === PAWN && b.color === turn) {
1399
- from = c;
1400
- flags = BITS.BIG_PAWN;
1401
- }
1402
- }
1403
- }
1404
- // promotion?
1405
- if (parse[5]) {
1406
- if(typeof parse[5][1] == 'undefined') {
1407
- promotion = parse[5][0].toLowerCase();
1408
- } else {
1409
- promotion = parse[5][1].toLowerCase();
1410
- }
1411
- }
1412
- }
1413
- if (from >=0 && to >=0 && flags) {
1414
- return build_move(board, from, to, flags, promotion);
1415
- } else if (move.length > 0) {
1416
- /* alert(move); // error in PGN, or in parsing. */
1417
- }
1418
- }
1419
-
1420
- function get_move_obj(move) {
1421
- return move_from_san(trim(move));
1422
- }
1423
-
1424
- function has_keys(object) {
1425
- var has_keys = false;
1426
- for (var key in object) {
1427
- has_keys = true;
1428
- }
1429
- return has_keys;
1430
- }
1431
-
1432
- function parse_pgn_header(header, options) {
1433
- var newline_char = (typeof options === 'object' &&
1434
- typeof options.newline_char === 'string') ?
1435
- options.newline_char : '\r?\n';
1436
- var header_obj = {};
1437
- var headers = header.split(newline_char);
1438
- var key = '';
1439
- var value = '';
1440
-
1441
- for (var i = 0; i < headers.length; i++) {
1442
- key = headers[i].replace(/^\[([A-Z][A-Za-z]*)\s.*\]$/, '$1');
1443
- value = headers[i].replace(/^\[[A-Za-z]+\s"(.*)"\]$/, '$1');
1444
- if (trim(key).length > 0) {
1445
- header_obj[key] = value;
1446
- }
1447
- }
1448
-
1449
- return header_obj;
1450
- }
1451
-
1452
- var newline_char = (typeof options === 'object' &&
1453
- typeof options.newline_char === 'string') ?
1454
- options.newline_char : '\r?\n';
1455
- var regex = new RegExp('^(\\[(.|' + mask(newline_char) + ')*\\])' +
1456
- '(' + mask(newline_char) + ')*' +
1457
- '1.(' + mask(newline_char) + '|.)*$', 'g');
1458
-
1459
- /* get header part of the PGN file */
1460
- var header_string = pgn.replace(regex, '$1');
1461
-
1462
- /* no info part given, begins with moves */
1463
- if (header_string[0] !== '[') {
1464
- header_string = '';
1465
- }
1466
-
1467
- reset();
1468
-
1469
- /* parse PGN header */
1470
- var headers = parse_pgn_header(header_string, options);
1471
- for (var key in headers) {
1472
- set_header([key, headers[key]]);
1473
- }
1474
-
1475
- /* delete header to get the moves */
1476
- var ms = pgn.replace(header_string, '').replace(new RegExp(mask(newline_char), 'g'), ' ');
1477
-
1478
- /* delete comments */
1479
- ms = ms.replace(/(\{[^}]+\})+?/g, '');
1480
-
1481
- /* delete move numbers */
1482
- ms = ms.replace(/\d+\./g, '');
1483
-
1484
-
1485
- /* trim and get array of moves */
1486
- var moves = trim(ms).split(new RegExp(/\s+/));
1487
-
1488
- /* delete empty entries */
1489
- moves = moves.join(',').replace(/,,+/g, ',').split(',');
1490
- var move = '';
1491
-
1492
- for (var half_move = 0; half_move < moves.length - 1; half_move++) {
1493
- move = get_move_obj(moves[half_move]);
1494
-
1495
- /* move not possible! (don't clear the board to examine to show the
1496
- * latest valid position)
1497
- */
1498
- if (move == null) {
1499
- return false;
1500
- } else {
1501
- make_move(move);
1502
- }
1503
- }
1504
-
1505
- /* examine last move */
1506
- move = moves[moves.length - 1];
1507
- if (POSSIBLE_RESULTS.indexOf(move) > -1) {
1508
- if (has_keys(header) && typeof header.Result === 'undefined') {
1509
- set_header(['Result', move]);
1510
- }
1511
- }
1512
- else {
1513
- move = get_move_obj(move);
1514
- if (move == null) {
1515
- return false;
1516
- } else {
1517
- make_move(move);
1518
- }
1519
- }
1520
- return true;
1521
- },
1522
-
1523
- header: function() {
1524
- return set_header(arguments);
1525
- },
1526
-
1527
- ascii: function() {
1528
- return ascii();
1529
- },
1530
-
1531
- turn: function() {
1532
- return turn;
1533
- },
1534
-
1535
- move: function(move) {
1536
- /* The move function can be called with in the following parameters:
1537
- *
1538
- * .move('Nxb7') <- where 'move' is a case-sensitive SAN string
1539
- *
1540
- * .move({ from: 'h7', <- where the 'move' is a move object (additional
1541
- * to :'h8', fields are ignored)
1542
- * promotion: 'q',
1543
- * })
1544
- */
1545
- var move_obj = null;
1546
- var moves = generate_moves();
1547
-
1548
- if (typeof move === 'string') {
1549
- /* convert the move string to a move object */
1550
- for (var i = 0, len = moves.length; i < len; i++) {
1551
- if (move === move_to_san(moves[i])) {
1552
- move_obj = moves[i];
1553
- break;
1554
- }
1555
- }
1556
- } else if (typeof move === 'object') {
1557
- /* convert the pretty move object to an ugly move object */
1558
- for (var i = 0, len = moves.length; i < len; i++) {
1559
- if (move.from === algebraic(moves[i].from) &&
1560
- move.to === algebraic(moves[i].to) &&
1561
- (!('promotion' in moves[i]) ||
1562
- move.promotion === moves[i].promotion)) {
1563
- move_obj = moves[i];
1564
- break;
1565
- }
1566
- }
1567
- }
1568
-
1569
- /* failed to find move */
1570
- if (!move_obj) {
1571
- return null;
1572
- }
1573
-
1574
- /* need to make a copy of move because we can't generate SAN after the
1575
- * move is made
1576
- */
1577
- var pretty_move = make_pretty(move_obj);
1578
-
1579
- make_move(move_obj);
1580
-
1581
- return pretty_move;
1582
- },
1583
-
1584
- undo: function() {
1585
- var move = undo_move();
1586
- return (move) ? make_pretty(move) : null;
1587
- },
1588
-
1589
- clear: function() {
1590
- return clear();
1591
- },
1592
-
1593
- put: function(piece, square) {
1594
- return put(piece, square);
1595
- },
1596
-
1597
- get: function(square) {
1598
- return get(square);
1599
- },
1600
-
1601
- remove: function(square) {
1602
- return remove(square);
1603
- },
1604
-
1605
- perft: function(depth) {
1606
- return perft(depth);
1607
- },
1608
-
1609
- square_color: function(square) {
1610
- if (square in SQUARES) {
1611
- var sq_0x88 = SQUARES[square];
1612
- return ((rank(sq_0x88) + file(sq_0x88)) % 2 === 0) ? 'light' : 'dark';
1613
- }
1614
-
1615
- return null;
1616
- },
1617
-
1618
- history: function(options) {
1619
- var reversed_history = [];
1620
- var move_history = [];
1621
- var verbose = (typeof options !== 'undefined' && 'verbose' in options &&
1622
- options.verbose);
1623
-
1624
- while (history.length > 0) {
1625
- reversed_history.push(undo_move());
1626
- }
1627
-
1628
- while (reversed_history.length > 0) {
1629
- var move = reversed_history.pop();
1630
- if (verbose) {
1631
- move_history.push(make_pretty(move));
1632
- } else {
1633
- move_history.push(move_to_san(move));
1634
- }
1635
- make_move(move);
1636
- }
1637
-
1638
- return move_history;
1639
- }
1640
-
1641
- };
1642
- };
1643
-
1644
- /* export Chess object if using node or any other CommonJS compatible
1645
- * environment */
1646
- if (typeof exports !== 'undefined') exports.Chess = Chess;