@alepot55/chessboardjs 2.1.5 → 2.1.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/chessboard.js CHANGED
@@ -47,16 +47,17 @@ class Chessboard {
47
47
  'invalid_hintColor': 'Invalid hintColor - ',
48
48
  }
49
49
 
50
+ // -------------------
51
+ // Initialization
52
+ // -------------------
50
53
  constructor(config) {
51
54
  this.config = new ChessboardConfig(config);
52
55
  this.init();
53
56
  }
54
57
 
55
- // Build
56
-
57
58
  init() {
58
59
  this.initParams();
59
- this.buildGame(this.config.position);
60
+ this.setGame(this.config.position);
60
61
  this.buildBoard();
61
62
  this.buildSquares();
62
63
  this.addListeners();
@@ -68,27 +69,13 @@ class Chessboard {
68
69
  this.squares = {};
69
70
  this.promoting = false;
70
71
  this.clicked = null;
71
- this.movesHistory = [];
72
72
  this.mosseIndietro = [];
73
73
  this.clicked = null;
74
74
  }
75
75
 
76
- buildGame(position) {
77
- if (typeof position === 'object') {
78
- this.game = new Chess('start');
79
- Object.entries(position).forEach(([square, [type, color]]) => {
80
- this.game.put({ type, color }, square);
81
- });
82
- } else if (Object.values(this.standard_positions).includes(position)) {
83
- if (position === 'start') this.game = new Chess();
84
- else this.game = new Chess(this.standard_positions[position]);
85
- } else if (validateFen(position)) {
86
- this.game = new Chess(position);
87
- } else {
88
- throw new Error(this.error_messages['invalid_position'] + position);
89
- }
90
- }
91
-
76
+ // -------------------
77
+ // Board Setup
78
+ // -------------------
92
79
  buildBoard() {
93
80
  this.board = document.getElementById(this.config.id_div);
94
81
  if (!this.board) {
@@ -98,12 +85,6 @@ class Chessboard {
98
85
  this.board.className = "board";
99
86
  }
100
87
 
101
- realCoord(row, col) {
102
- if (this.isWhiteOriented()) row = 7 - row;
103
- else col = 7 - col;
104
- return [row + 1, col + 1];
105
- }
106
-
107
88
  buildSquares() {
108
89
 
109
90
  for (let row = 0; row < 8; row++) {
@@ -123,8 +104,80 @@ class Chessboard {
123
104
  this.board.innerHTML = '';
124
105
  }
125
106
 
126
- // Pieces
107
+ removeSquares() {
108
+ for (const square of Object.values(this.squares)) {
109
+ this.board.removeChild(square.element);
110
+ square.destroy();
111
+
112
+ }
113
+ this.squares = {};
114
+ }
115
+
116
+ resize(value) {
117
+ if (value === 'auto') {
118
+ let size;
119
+ if (this.board.offsetWidth === 0) {
120
+ size = this.board.offsetHeight;
121
+ } else if (this.board.offsetHeight === 0) {
122
+ size = this.board.offsetWidth;
123
+ } else {
124
+ size = Math.min(this.board.offsetWidth, this.board.offsetHeight);
125
+ }
126
+ this.resize(size);
127
+ } else if (typeof value !== 'number') {
128
+ throw new Error(this.error_messages['invalid_value'] + value);
129
+ } else {
130
+ document.documentElement.style.setProperty('--dimBoard', value + 'px');
131
+ this.updateBoardPieces();
132
+ }
133
+ }
134
+
135
+ // -------------------
136
+ // Game/Position Functions
137
+ // -------------------
138
+ convertFen(position) {
139
+ if (typeof position === 'string') {
140
+
141
+ if (this.validateFen(position)) return position;
142
+ else if (this.standard_positions[position]) return this.standard_positions[position];
143
+ else throw new Error('Invalid position -' + position);
144
+ } else if (typeof position === 'object') {
145
+ let parts = [];
146
+ for (let row = 0; row < 8; row++) {
147
+ let rowParts = [];
148
+ let empty = 0;
149
+ for (let col = 0; col < 8; col++) {
150
+ let square = this.getSquareID(row, col);
151
+ let piece = position[square];
152
+ if (piece) {
153
+ if (empty > 0) {
154
+ rowParts.push(empty);
155
+ empty = 0;
156
+ }
157
+ // Convert piece notation: white pieces become uppercase, black remain lowercase.
158
+ let fenPiece = piece[1] === 'w' ? piece[0].toUpperCase() : piece[0].toLowerCase();
159
+ rowParts.push(fenPiece);
160
+ } else {
161
+ empty++;
162
+ }
163
+ }
164
+ if (empty > 0) rowParts.push(empty);
165
+ parts.push(rowParts.join(''));
166
+ }
167
+ return parts.join('/');
168
+ } else {
169
+ throw new Error('Invalid position -' + position);
170
+ }
171
+ }
172
+
173
+ setGame(position) {
174
+ const fen = this.convertFen(position);
175
+ this.game = new Chess(fen === 'start' ? this.standard_positions['default'] : null);
176
+ }
127
177
 
178
+ // -------------------
179
+ // Piece Functions
180
+ // -------------------
128
181
  getPiecePath(piece) {
129
182
  if (typeof this.config.piecesPath === 'string')
130
183
  return this.config.piecesPath + '/' + piece + '.svg';
@@ -136,41 +189,27 @@ class Chessboard {
136
189
  throw new Error(this.error_messages['invalid_piecesPath']);
137
190
  }
138
191
 
139
- colorPiece(square) {
140
- let piece = this.piece(square);
141
- return piece ? piece[1] : null;
142
- }
143
-
144
- movePiece(piece, to, duration, callback) {
145
- piece.translate(to, duration, this.transitionTimingFunction, this.config.moveAnimation, callback);
146
- }
147
-
148
- translatePiece(move, removeTo, animate, callback = null) {
149
-
150
- if (removeTo) this.removePieceFromSquare(move.to, false);
151
-
152
- let change_square = () => {
153
- move.from.removePiece();
154
- move.to.putPiece(move.piece);
155
- move.piece.setDrag(this.dragFunction(move.to, move.piece));
156
- if (callback) callback();
192
+ convertPiece(piece) {
193
+ if (piece instanceof Piece) return piece;
194
+ if (typeof piece === 'string') {
195
+ let [type, color] = piece.split('');
196
+ return new Piece(color, type, this.getPiecePath(piece));
157
197
  }
198
+ throw new Error(this.error_messages['invalid_piece'] + piece);
199
+ }
158
200
 
159
- let duration = animate ? this.config.moveTime : 0;
160
-
161
- this.movePiece(move.piece, move.to, duration, change_square);
201
+ addPieceOnSquare(square, piece, fade = true) {
162
202
 
163
- }
203
+ square.putPiece(piece);
204
+ piece.setDrag(this.dragFunction(square, piece));
164
205
 
165
- snapbackPiece(square, animate) {
166
- let move = new Move(square, square);
167
- this.translatePiece(move, false, animate);
168
- }
206
+ if (fade) piece.fadeIn(
207
+ this.config.fadeTime,
208
+ this.config.fadeAnimation,
209
+ this.transitionTimingFunction
210
+ );
169
211
 
170
- convertSquare(square) {
171
- if (square instanceof Square) return square;
172
- if (typeof square === 'string' && this.squares[square]) return this.squares[square];
173
- throw new Error('Invalid square value');
212
+ piece.visible();
174
213
  }
175
214
 
176
215
  removePieceFromSquare(square, fade = true) {
@@ -192,110 +231,35 @@ class Chessboard {
192
231
  return piece;
193
232
  }
194
233
 
195
- dragFunction(square, piece) {
196
-
197
- return (event) => {
198
-
199
- event.preventDefault();
200
-
201
- if (!this.config.draggable || !piece) return;
202
- if (!this.config.onDragStart(square, piece)) return;
203
-
204
- let prec;
205
- let from = square;
206
- let to = square;
207
-
208
- const img = piece.element;
209
-
210
- if (!this.canMove(from)) return;
211
- if (!this.config.clickable) this.clicked = null;
212
- if (this.onClick(from)) return;
213
-
214
- img.style.position = 'absolute';
215
- img.style.zIndex = 100;
216
-
217
- const moveAt = (pageX, pageY) => {
218
- const halfWidth = img.offsetWidth / 2;
219
- const halfHeight = img.offsetHeight / 2;
220
- img.style.left = `${pageX - halfWidth}px`;
221
- img.style.top = `${pageY - halfHeight}px`;
222
- return true;
223
- };
224
-
225
- const onMouseMove = (event) => {
226
- if (!moveAt(event.pageX, event.pageY)) return;
227
-
228
- const boardRect = this.board.getBoundingClientRect();
229
- const { offsetWidth: boardWidth, offsetHeight: boardHeight } = this.board;
230
- const x = event.clientX - boardRect.left;
231
- const y = event.clientY - boardRect.top;
232
-
233
- let newTo = null;
234
- if (x >= 0 && x <= boardWidth && y >= 0 && y <= boardHeight) {
235
- const col = Math.floor(x / (boardWidth / 8));
236
- const row = Math.floor(y / (boardHeight / 8));
237
- newTo = this.squares[this.getSquareID(row, col)];
238
- }
239
-
240
- to = newTo;
241
- this.config.onDragMove(from, to, piece);
242
-
243
- if (to !== prec) {
244
- to?.highlight();
245
- prec?.dehighlight();
246
- prec = to;
247
- }
248
- };
249
-
250
- const onMouseUp = () => {
251
- prec?.dehighlight();
252
- document.removeEventListener('mousemove', onMouseMove);
253
- window.removeEventListener('mouseup', onMouseUp);
254
- img.style.zIndex = 20;
255
-
256
- const dropResult = this.config.onDrop(from, to, piece);
257
- const isTrashDrop = !to && (this.config.dropOffBoard === 'trash' || dropResult === 'trash');
234
+ movePiece(piece, to, duration, callback) {
235
+ piece.translate(to, duration, this.transitionTimingFunction, this.config.moveAnimation, callback);
236
+ }
258
237
 
259
- if (isTrashDrop) {
260
- this.allSquares("unmoved");
261
- this.allSquares('removeHint');
262
- from.deselect();
263
- this.remove(from);
264
- } else if (!to || !this.onClick(to, true)) {
265
- this.snapbackPiece(from, !this.promoting);
266
- this.config.onSnapbackEnd(from, piece);
267
- }
268
- };
238
+ translatePiece(move, removeTo, animate, callback = null) {
269
239
 
270
- window.addEventListener('mouseup', onMouseUp, { once: true });
271
- document.addEventListener('mousemove', onMouseMove);
272
- img.addEventListener('mouseup', onMouseUp, { once: true });
273
- }
274
- }
240
+ if (removeTo) this.removePieceFromSquare(move.to, false);
275
241
 
276
- convertPiece(piece) {
277
- if (piece instanceof Piece) return piece;
278
- if (typeof piece === 'string') {
279
- let [type, color] = piece.split('');
280
- return new Piece(color, type, this.getPiecePath(piece));
242
+ let change_square = () => {
243
+ move.from.removePiece();
244
+ move.to.putPiece(move.piece);
245
+ move.piece.setDrag(this.dragFunction(move.to, move.piece));
246
+ if (callback) callback();
281
247
  }
282
- throw new Error(this.error_messages['invalid_piece'] + piece);
283
- }
284
248
 
285
- addPieceOnSquare(square, piece, fade = true) {
249
+ let duration = animate ? this.config.moveTime : 0;
286
250
 
287
- square.putPiece(piece);
288
- piece.setDrag(this.dragFunction(square, piece));
251
+ this.movePiece(move.piece, move.to, duration, change_square);
289
252
 
290
- if (fade) piece.fadeIn(
291
- this.config.fadeTime,
292
- this.config.fadeAnimation,
293
- this.transitionTimingFunction
294
- );
253
+ }
295
254
 
296
- piece.visible();
255
+ snapbackPiece(square, animate) {
256
+ let move = new Move(square, square);
257
+ this.translatePiece(move, false, animate);
297
258
  }
298
259
 
260
+ // -------------------
261
+ // Board Update Functions
262
+ // -------------------
299
263
  updateBoardPieces(animation = false) {
300
264
  let { updatedFlags, escapeFlags, movableFlags, pendingTranslations } = this.prepareBoardUpdateData();
301
265
 
@@ -315,9 +279,9 @@ class Chessboard {
315
279
  for (let squareId in this.squares) {
316
280
  let cellPiece = this.squares[squareId].piece;
317
281
  let cellPieceId = cellPiece ? cellPiece.getId() : null;
318
- updatedFlags[squareId] = this.piece(squareId) === cellPieceId;
282
+ updatedFlags[squareId] = this.getGamePieceId(squareId) === cellPieceId;
319
283
  escapeFlags[squareId] = false;
320
- movableFlags[squareId] = cellPiece ? this.piece(squareId) !== cellPieceId : false;
284
+ movableFlags[squareId] = cellPiece ? this.getGamePieceId(squareId) !== cellPieceId : false;
321
285
  }
322
286
 
323
287
  return { updatedFlags, escapeFlags, movableFlags, pendingTranslations };
@@ -325,7 +289,7 @@ class Chessboard {
325
289
 
326
290
  identifyPieceTranslations(updatedFlags, escapeFlags, movableFlags, pendingTranslations) {
327
291
  Object.values(this.squares).forEach(targetSquare => {
328
- const newPieceId = this.piece(targetSquare.id);
292
+ const newPieceId = this.getGamePieceId(targetSquare.id);
329
293
  const newPiece = newPieceId && this.convertPiece(newPieceId);
330
294
  const currentPiece = targetSquare.piece;
331
295
  const currentPieceId = currentPiece ? currentPiece.getId() : null;
@@ -370,7 +334,7 @@ class Chessboard {
370
334
 
371
335
  pendingTranslations.push([currentSource, sourceSquare, targetSquare]);
372
336
 
373
- if (!this.piece(sourceSquare.id)) updatedFlags[sourceSquare.id] = true;
337
+ if (!this.getGamePieceId(sourceSquare.id)) updatedFlags[sourceSquare.id] = true;
374
338
 
375
339
  escapeFlags[sourceSquare.id] = true;
376
340
  movableFlags[sourceSquare.id] = false;
@@ -379,7 +343,6 @@ class Chessboard {
379
343
 
380
344
  executePieceTranslations(pendingTranslations, escapeFlags, animation) {
381
345
  for (let [_, sourceSquare, targetSquare] of pendingTranslations) {
382
- console.log('executing translation: ', sourceSquare.id, targetSquare.id);
383
346
  let removeTarget = !escapeFlags[targetSquare.id] && targetSquare.piece;
384
347
  let moveObj = new Move(sourceSquare, targetSquare);
385
348
  this.translatePiece(moveObj, removeTarget, animation);
@@ -389,7 +352,7 @@ class Chessboard {
389
352
  // Gestisce gli aggiornamenti residui per ogni cella che non è ancora stata correttamente aggiornata
390
353
  processRemainingPieceUpdates(updatedFlags, animation) {
391
354
  for (const square of Object.values(this.squares)) {
392
- let newPieceId = this.piece(square.id);
355
+ let newPieceId = this.getGamePieceId(square.id);
393
356
  let newPiece = newPieceId ? this.convertPiece(newPieceId) : null;
394
357
  let currentPiece = square.piece;
395
358
  let currentPieceId = currentPiece ? currentPiece.getId() : null;
@@ -422,48 +385,128 @@ class Chessboard {
422
385
  }
423
386
  }
424
387
 
425
- isPiece(piece, square) { return this.piece(square) === piece }
426
-
427
- // Listeners
388
+ // -------------------
389
+ // Event Handlers and Drag
390
+ // -------------------
391
+ dragFunction(square, piece) {
428
392
 
429
- addListeners() {
430
- for (const square of Object.values(this.squares)) {
393
+ return (event) => {
431
394
 
432
- let piece = square.piece;
395
+ event.preventDefault();
433
396
 
434
- square.element.addEventListener("mouseover", (e) => {
435
- if (!this.clicked) this.hintMoves(square);
436
- });
437
- square.element.addEventListener("mouseout", (e) => {
438
- if (!this.clicked) this.dehintMoves(square);
439
- });
397
+ if (!this.config.draggable || !piece) return;
398
+ if (!this.config.onDragStart(square, piece)) return;
440
399
 
441
- const handleClick = (e) => {
442
- e.stopPropagation();
443
- if (this.config.clickable && (!piece || this.config.onlyLegalMoves)) this.onClick(square)
444
- }
400
+ let prec;
401
+ let from = square;
402
+ let to = square;
445
403
 
446
- square.element.addEventListener("click", handleClick);
447
- square.element.addEventListener("touch", handleClick);
448
- }
449
- }
404
+ const img = piece.element;
450
405
 
451
- onClick(square, animation = this.config.moveAnimation) {
406
+ if (!this.canMove(from)) return;
407
+ if (!this.config.clickable) this.clicked = null;
408
+ if (this.onClick(from)) return;
452
409
 
453
- if (square.id === this.clicked?.id) return false;
410
+ img.style.position = 'absolute';
411
+ img.style.zIndex = 100;
454
412
 
455
- let from = this.clicked;
456
- this.clicked = null;
413
+ const moveAt = (pageX, pageY) => {
414
+ const halfWidth = img.offsetWidth / 2;
415
+ const halfHeight = img.offsetHeight / 2;
416
+ img.style.left = `${pageX - halfWidth}px`;
417
+ img.style.top = `${pageY - halfHeight}px`;
418
+ return true;
419
+ };
457
420
 
458
- let promotion = null
421
+ const onMouseMove = (event) => {
422
+ if (!moveAt(event.pageX, event.pageY)) return;
459
423
 
460
- if (this.promoting) {
461
- if (this.promoting === 'none') from = null
462
- else promotion = this.promoting;
424
+ const boardRect = this.board.getBoundingClientRect();
425
+ const { offsetWidth: boardWidth, offsetHeight: boardHeight } = this.board;
426
+ const x = event.clientX - boardRect.left;
427
+ const y = event.clientY - boardRect.top;
463
428
 
464
- this.promoting = false;
465
- this.allSquares("removePromotion");
466
- this.allSquares("removeCover");
429
+ let newTo = null;
430
+ if (x >= 0 && x <= boardWidth && y >= 0 && y <= boardHeight) {
431
+ const col = Math.floor(x / (boardWidth / 8));
432
+ const row = Math.floor(y / (boardHeight / 8));
433
+ newTo = this.squares[this.getSquareID(row, col)];
434
+ }
435
+
436
+ to = newTo;
437
+ this.config.onDragMove(from, to, piece);
438
+
439
+ if (to !== prec) {
440
+ to?.highlight();
441
+ prec?.dehighlight();
442
+ prec = to;
443
+ }
444
+ };
445
+
446
+ const onMouseUp = () => {
447
+ prec?.dehighlight();
448
+ document.removeEventListener('mousemove', onMouseMove);
449
+ window.removeEventListener('mouseup', onMouseUp);
450
+ img.style.zIndex = 20;
451
+
452
+ const dropResult = this.config.onDrop(from, to, piece);
453
+ const isTrashDrop = !to && (this.config.dropOffBoard === 'trash' || dropResult === 'trash');
454
+
455
+ if (isTrashDrop) {
456
+ this.allSquares("unmoved");
457
+ this.allSquares('removeHint');
458
+ from.deselect();
459
+ this.remove(from);
460
+ } else if (!to || !this.onClick(to, true)) {
461
+ this.snapbackPiece(from, !this.promoting);
462
+ this.config.onSnapbackEnd(from, piece);
463
+ }
464
+ };
465
+
466
+ window.addEventListener('mouseup', onMouseUp, { once: true });
467
+ document.addEventListener('mousemove', onMouseMove);
468
+ img.addEventListener('mouseup', onMouseUp, { once: true });
469
+ }
470
+ }
471
+
472
+ addListeners() {
473
+ for (const square of Object.values(this.squares)) {
474
+
475
+ let piece = square.piece;
476
+
477
+ square.element.addEventListener("mouseover", (e) => {
478
+ if (!this.clicked) this.hintMoves(square);
479
+ });
480
+ square.element.addEventListener("mouseout", (e) => {
481
+ if (!this.clicked) this.dehintMoves(square);
482
+ });
483
+
484
+ const handleClick = (e) => {
485
+ e.stopPropagation();
486
+ if (this.config.clickable && (!piece || this.config.onlyLegalMoves)) this.onClick(square)
487
+ }
488
+
489
+ square.element.addEventListener("click", handleClick);
490
+ square.element.addEventListener("touch", handleClick);
491
+ }
492
+ }
493
+
494
+ onClick(square, animation = this.config.moveAnimation) {
495
+
496
+ if (square.id === this.clicked?.id) return false;
497
+
498
+ let from = this.clicked;
499
+ this.clicked = null;
500
+
501
+ let promotion = null
502
+
503
+ if (this.promoting) {
504
+ if (this.promoting === 'none') from = null
505
+ else promotion = this.promoting;
506
+
507
+ this.promoting = false;
508
+ this.allSquares("removePromotion");
509
+ this.allSquares("removeCover");
467
510
  }
468
511
 
469
512
  if (!from) {
@@ -496,31 +539,9 @@ class Chessboard {
496
539
  return false;
497
540
  }
498
541
 
499
- // Hint
500
-
501
- hint(square) {
502
- if (!this.config.hints || !this.squares[square]) return;
503
- this.squares[square].putHint(this.colorPiece(square) && this.colorPiece(square) !== this.turn());
504
- }
505
-
506
- hintMoves(square) {
507
- if (!this.canMove(square)) return;
508
- let mosse = this.game.moves({ square: square.id, verbose: true });
509
- for (let mossa of mosse) {
510
- if (mossa['to'].length === 2) this.hint(mossa['to']);
511
- }
512
- }
513
-
514
- dehintMoves(square) {
515
- let mosse = this.game.moves({ square: square.id, verbose: true });
516
- for (let mossa of mosse) {
517
- let to = this.squares[mossa['to']];
518
- to.removeHint();
519
- }
520
- }
521
-
522
- // Moves
523
-
542
+ // -------------------
543
+ // Move Functions
544
+ // -------------------
524
545
  canMove(square) {
525
546
  if (!square.piece) return false;
526
547
  if (this.config.movableColors === 'none') return false;
@@ -541,13 +562,6 @@ class Chessboard {
541
562
  throw new Error("Invalid move format");
542
563
  }
543
564
 
544
- allSquares(method) {
545
- for (const square of Object.values(this.squares)) {
546
- square[method]();
547
- this.squares[square.id] = square;
548
- }
549
- }
550
-
551
565
  legalMove(move) {
552
566
  let legal_moves = this.legalMoves(move.from.id);
553
567
 
@@ -565,50 +579,72 @@ class Chessboard {
565
579
  return this.game.moves({ verbose: verb });
566
580
  }
567
581
 
568
- // Position
582
+ move(move, animation) {
583
+ move = this.convertMove(move);
584
+ move.check();
569
585
 
570
- chageFenTurn(fen, color) {
571
- let parts = fen.split(' ');
572
- parts[1] = color;
573
- return parts.join(' ');
574
- }
586
+ let from = move.from;
587
+ let to = move.to;
575
588
 
576
- changeFenColor(fen) {
577
- let parts = fen.split(' ');
578
- parts[1] = parts[1] === 'w' ? 'b' : 'w';
579
- return parts.join(' ');
580
- }
589
+ if (!this.config.onlyLegalMoves) {
590
+ let piece = this.getGamePieceId(from.id);
591
+ this.game.remove(from.id);
592
+ this.game.remove(to.id);
593
+ this.game.put({ type: move.hasPromotion() ? move.promotion : piece[0], color: piece[1] }, to.id);
594
+ this.updateBoardPieces(animation);
595
+ } else {
596
+ this.allSquares("unmoved");
581
597
 
582
- playerTurn() {
583
- return this.getOrientation() == this.game.turn()
598
+ move = this.game.move({
599
+ from: from.id,
600
+ to: to.id,
601
+ promotion: move.hasPromotion() ? move.promotion : undefined
602
+ });
603
+
604
+ if (move === null) {
605
+ throw new Error("Invalid move: move could not be executed");
606
+ }
607
+
608
+ this.updateBoardPieces(animation);
609
+
610
+ from.moved();
611
+ to.moved();
612
+ this.allSquares("removeHint");
613
+
614
+ this.config.onMoveEnd(move);
615
+ }
584
616
  }
585
617
 
586
- isWhiteOriented() { return this.config.orientation === 'w' }
618
+ // -------------------
619
+ // Miscellaneous Functions
620
+ // -------------------
621
+ hint(squareId) {
622
+ let square = this.squares[squareId];
623
+ if (!this.config.hints || !square) return;
624
+ square.putHint(square.piece && square.piece.color !== this.turn());
625
+ }
587
626
 
588
- // Squares
627
+ hintMoves(square) {
628
+ if (!this.canMove(square)) return;
629
+ let mosse = this.game.moves({ square: square.id, verbose: true });
630
+ for (let mossa of mosse) {
631
+ if (mossa['to'].length === 2) this.hint(mossa['to']);
632
+ }
633
+ }
589
634
 
590
- getSquareID(row, col) {
591
- row = parseInt(row);
592
- col = parseInt(col);
593
- if (this.isWhiteOriented()) {
594
- row = 8 - row;
595
- col = col + 1;
596
- } else {
597
- row = row + 1;
598
- col = 8 - col;
635
+ dehintMoves(square) {
636
+ let mosse = this.game.moves({ square: square.id, verbose: true });
637
+ for (let mossa of mosse) {
638
+ let to = this.squares[mossa['to']];
639
+ to.removeHint();
599
640
  }
600
- let letters = 'abcdefgh';
601
- let letter = letters[col - 1];
602
- return letter + row;
603
641
  }
604
642
 
605
- removeSquares() {
643
+ allSquares(method) {
606
644
  for (const square of Object.values(this.squares)) {
607
- this.board.removeChild(square.element);
608
- square.destroy();
609
-
645
+ square[method]();
646
+ this.squares[square.id] = square;
610
647
  }
611
- this.squares = {};
612
648
  }
613
649
 
614
650
  promote(move) {
@@ -666,57 +702,72 @@ class Chessboard {
666
702
  }
667
703
  }
668
704
 
669
- // user
670
-
671
- turn() {
672
- return this.game.turn();
705
+ clearSquares() {
706
+ this.allSquares('removeHint');
707
+ this.allSquares("deselect");
708
+ this.allSquares("unmoved");
673
709
  }
674
710
 
675
- getOrientation() {
676
- return this.config.orientation;
711
+ getGamePieceId(squareId) {
712
+ let piece = this.game.get(squareId);
713
+ return piece ? piece['type'] + piece['color'] : null;
677
714
  }
678
715
 
679
- fen() {
680
- return this.game.fen();
681
- }
716
+ isPiece(piece, square) { return this.getGamePieceId(square) === piece }
682
717
 
683
- lastMove() {
684
- return this.movesHistory[this.movesHistory.length - 1];
718
+ realCoord(row, col) {
719
+ if (this.isWhiteOriented()) row = 7 - row;
720
+ else col = 7 - col;
721
+ return [row + 1, col + 1];
685
722
  }
686
723
 
687
- get history() {
688
- return this.movesHistory;
724
+ getSquareID(row, col) {
725
+ row = parseInt(row);
726
+ col = parseInt(col);
727
+ if (this.isWhiteOriented()) {
728
+ row = 8 - row;
729
+ col = col + 1;
730
+ } else {
731
+ row = row + 1;
732
+ col = 8 - col;
733
+ }
734
+ let letters = 'abcdefgh';
735
+ let letter = letters[col - 1];
736
+ return letter + row;
689
737
  }
690
738
 
691
- history() {
692
- return this.movesHistory;
739
+ convertSquare(square) {
740
+ if (square instanceof Square) return square;
741
+ if (typeof square === 'string' && this.squares[square]) return this.squares[square];
742
+ throw new Error(this.error_messages['invalid_square'] + square);
693
743
  }
694
744
 
695
- get(square) {
696
- square = this.convertSquare(square);
697
- square.check();
698
- let piece = square.piece;
699
- return piece ? piece.id : null;
745
+ // -------------------
746
+ // User API and Chess.js Integration
747
+ // -------------------
748
+ getOrientation() {
749
+ return this.config.orientation;
700
750
  }
701
751
 
702
- position(position, color = null) {
703
- this.allSquares('removeHint');
704
- this.allSquares("deselect");
705
- this.allSquares("unmoved");
706
- if (color && color !== this.config.orientation) {
707
- position = this.changeFenColor(position);
752
+ setOrientation(color, animation = true) {
753
+ if (!['w', 'b'].includes(color)) {
708
754
  this.config.orientation = color;
709
- this.destroy();
710
- this.init();
755
+ this.flip(animation);
711
756
  } else {
712
- this.buildGame(this.config.position);
713
- this.updateBoardPieces();
757
+ throw new Error(this.error_messages['invalid_orientation'] + color);
714
758
  }
715
759
  }
716
760
 
761
+ lastMove() {
762
+ const moves = this.history({ verbose: true });
763
+ return moves[moves.length - 1];
764
+ }
765
+
717
766
  flip() {
718
- let position = this.game.fen();
719
- this.position(position, this.config.orientation === 'w' ? 'b' : 'w');
767
+ this.config.orientation = this.config.orientation === 'w' ? 'b' : 'w';
768
+ this.destroy();
769
+ this.initParams();
770
+ this.build();
720
771
  }
721
772
 
722
773
  build() {
@@ -724,127 +775,179 @@ class Chessboard {
724
775
  this.init();
725
776
  }
726
777
 
727
- move(move, animation) {
728
- move = this.convertMove(move);
729
- move.check();
778
+ destroy() {
779
+ this.removeSquares();
780
+ this.removeBoard();
781
+ }
730
782
 
731
- let from = move.from;
732
- let to = move.to;
783
+ ascii() {
784
+ return this.game.ascii();
785
+ }
733
786
 
734
- if (!this.config.onlyLegalMoves) {
735
- let piece = this.piece(from.id);
736
- this.game.remove(from.id);
737
- this.game.remove(to.id);
738
- this.game.put({ type: move.hasPromotion() ? move.promotion : piece[0], color: piece[1] }, to.id);
739
- this.updateBoardPieces(animation);
740
- } else {
741
- this.allSquares("unmoved");
787
+ board() {
788
+ return this.game.board();
789
+ }
742
790
 
743
- move = this.game.move({
744
- from: from.id,
745
- to: to.id,
746
- promotion: move.hasPromotion() ? move.promotion : undefined
747
- });
791
+ clear(options = {}, animation = true) {
792
+ this.game.clear(options);
793
+ this.updateBoardPieces(animation);
794
+ }
748
795
 
749
- if (move === null) {
750
- throw new Error("Invalid move: move could not be executed");
751
- }
796
+ fen() {
797
+ return this.game.fen();
798
+ }
752
799
 
753
- this.movesHistory.push(move);
800
+ get(squareId) {
801
+ const square = this.convertSquare(squareId);
802
+ square.check();
803
+ return square.piece;
804
+ }
754
805
 
755
- this.updateBoardPieces(animation);
806
+ getCastlingRights(color) {
807
+ return this.game.getCastlingRights(color);
808
+ }
756
809
 
757
- from.moved();
758
- to.moved();
759
- this.allSquares("removeHint");
810
+ getComment() {
811
+ return this.game.getComment();
812
+ }
760
813
 
761
- this.config.onMoveEnd(move);
762
- }
814
+ getComments() {
815
+ return this.game.getComments();
816
+ }
817
+
818
+ history(options = {}) {
819
+ return this.game.history(options);
820
+ }
821
+
822
+ isCheckmate() {
823
+ return this.game.isCheckmate();
824
+ }
825
+
826
+ isDraw() {
827
+ return this.game.isDraw();
828
+ }
829
+
830
+ isDrawByFiftyMoves() {
831
+ return this.game.isDrawByFiftyMoves();
832
+ }
833
+
834
+ isInsufficientMaterial() {
835
+ return this.game.isInsufficientMaterial();
836
+ }
837
+
838
+ isGameOver() {
839
+ return this.game.isGameOver();
840
+ }
841
+
842
+ isStalemate() {
843
+ return this.game.isStalemate();
763
844
  }
764
845
 
765
- clear(animation = true) {
766
- this.game.clear();
846
+ isThreefoldRepetition() {
847
+ return this.game.isThreefoldRepetition();
848
+ }
849
+
850
+ load(fen, options = {}, animation = true) {
851
+ this.clearSquares();
852
+ this.game.load(fen, options);
767
853
  this.updateBoardPieces(animation);
768
854
  }
769
855
 
770
- insert(square, piece) {
771
- square = this.convertSquare(square);
772
- piece = this.convertPiece(piece);
773
- square.check();
774
- piece.check();
775
- if (square.piece) this.remove(square);
776
- this.game.put({ type: piece.type, color: piece.color }, square.id);
856
+ loadPgn(pgn, options = {}, animation = true) {
857
+ this.clearSquares();
858
+ this.game.loadPgn(pgn, options);
777
859
  this.updateBoardPieces();
778
860
  }
779
861
 
780
- isGameOver() {
781
- if (this.game.isGameOver()) {
782
- if (this.game.inCheck()) return this.game.turn() === 'w' ? 'b' : 'w';
783
- return 'd';
784
- }
785
- return null;
862
+ moveNumber() {
863
+ return this.game.moveNumber();
786
864
  }
787
865
 
788
- orientation(color) {
789
- if ((color === 'w' || color === 'b') && color !== this.config.orientation) this.flip();
866
+ moves(options = {}) {
867
+ return this.game.moves(options);
790
868
  }
791
869
 
792
- resize(value) {
793
- if (value === 'auto') {
794
- let size;
795
- if (this.board.offsetWidth === 0) {
796
- size = this.board.offsetHeight;
797
- } else if (this.board.offsetHeight === 0) {
798
- size = this.board.offsetWidth;
799
- } else {
800
- size = Math.min(this.board.offsetWidth, this.board.offsetHeight);
801
- }
802
- this.resize(size);
803
- } else if (typeof value !== 'number') {
804
- throw new Error(this.error_messages['invalid_value'] + value);
805
- } else {
806
- document.documentElement.style.setProperty('--dimBoard', value + 'px');
807
- this.updateBoardPieces();
808
- }
870
+ pgn(options = {}) {
871
+ return this.game.pgn(options);
809
872
  }
810
873
 
811
- destroy() {
812
- this.removeSquares();
813
- this.removeBoard();
814
- this.game = null;
815
- this.clicked = null;
816
- this.movesHistory = [];
817
- this.mosseIndietro = [];
818
- this.clicked = null;
819
- this.board = null;
874
+ put(pieceId, squareId, animation = true) {
875
+ const [type, color] = pieceId.split('');
876
+ const success = this.game.put({ type: type, color: color }, squareId);
877
+ if (success) this.updateBoardPieces(animation);
878
+ return success;
820
879
  }
821
880
 
822
- remove(square, animation = true) {
823
- square = this.convertSquare(square);
824
- square.check();
825
- this.game.remove(square.id);
826
- let piece = square.piece;
881
+ remove(squareId, animation = true) {
882
+ const removedPiece = this.game.remove(squareId);
827
883
  this.updateBoardPieces(animation);
828
- return piece;
884
+ return removedPiece;
829
885
  }
830
886
 
831
- piece(square) {
832
- let piece = this.game.get(square);
833
- return piece ? piece['type'] + piece['color'] : null;
887
+ removeComment() {
888
+ return this.game.removeComment();
834
889
  }
835
890
 
836
- highlight(square) {
837
- square = this.convertSquare(square);
838
- square.check();
839
- square.highlight();
891
+ removeComments() {
892
+ return this.game.removeComments();
840
893
  }
841
894
 
842
- dehighlight(square) {
843
- square = this.convertSquare(square);
844
- square.check();
845
- square.dehighlight();
895
+ removeHeader(field) {
896
+ return this.game.removeHeader(field);
897
+ }
898
+
899
+ reset(animation = true) {
900
+ this.game.reset();
901
+ this.updateBoardPieces(animation);
902
+ }
903
+
904
+ setCastlingRights(color, rights) {
905
+ return this.game.setCastlingRights(color, rights);
906
+ }
907
+
908
+ setComment(comment) {
909
+ this.game.setComment(comment);
910
+ }
911
+
912
+ setHeader(key, value) {
913
+ return this.game.setHeader(key, value);
914
+ }
915
+
916
+ squareColor(squareId) {
917
+ return this.game.squareColor(squareId);
846
918
  }
847
919
 
920
+ turn() {
921
+ return this.game.turn();
922
+ }
923
+
924
+ undo() {
925
+ const move = this.game.undo();
926
+ if (move) this.updateBoardPieces();
927
+ return move;
928
+ }
929
+
930
+ validateFen(fen) {
931
+ return validateFen(fen);
932
+ }
933
+
934
+ // -------------------
935
+ // Other Utility Functions
936
+ // -------------------
937
+ chageFenTurn(fen, color) {
938
+ let parts = fen.split(' ');
939
+ parts[1] = color;
940
+ return parts.join(' ');
941
+ }
942
+
943
+ changeFenColor(fen) {
944
+ let parts = fen.split(' ');
945
+ parts[1] = parts[1] === 'w' ? 'b' : 'w';
946
+ return parts.join(' ');
947
+ }
948
+
949
+ isWhiteOriented() { return this.config.orientation === 'w' }
950
+
848
951
  }
849
952
 
850
953
  export default Chessboard;