@alepot55/chessboardjs 2.2.1 → 2.3.0

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.
Files changed (74) hide show
  1. package/README.md +125 -401
  2. package/assets/themes/alepot/theme.json +42 -0
  3. package/assets/themes/default/theme.json +42 -0
  4. package/dist/chessboard.cjs.js +11785 -0
  5. package/dist/chessboard.css +243 -0
  6. package/dist/chessboard.esm.js +11716 -0
  7. package/dist/chessboard.iife.js +11791 -0
  8. package/dist/chessboard.umd.js +11791 -0
  9. package/package.json +33 -3
  10. package/{chessboard.move.js → src/components/Move.js} +3 -3
  11. package/src/components/Piece.js +771 -0
  12. package/{chessboard.square.js → src/components/Square.js} +61 -8
  13. package/src/constants/index.js +15 -0
  14. package/src/constants/positions.js +62 -0
  15. package/src/core/Chessboard.js +2346 -0
  16. package/src/core/ChessboardConfig.js +707 -0
  17. package/src/core/ChessboardFactory.js +385 -0
  18. package/src/core/index.js +141 -0
  19. package/src/errors/ChessboardError.js +133 -0
  20. package/src/errors/index.js +15 -0
  21. package/src/errors/messages.js +189 -0
  22. package/src/index.js +103 -0
  23. package/src/services/AnimationService.js +180 -0
  24. package/src/services/BoardService.js +156 -0
  25. package/src/services/CoordinateService.js +355 -0
  26. package/src/services/EventService.js +955 -0
  27. package/src/services/MoveService.js +567 -0
  28. package/src/services/PieceService.js +339 -0
  29. package/src/services/PositionService.js +237 -0
  30. package/src/services/ValidationService.js +673 -0
  31. package/src/services/index.js +14 -0
  32. package/src/styles/animations.css +46 -0
  33. package/{chessboard.css → src/styles/board.css} +30 -7
  34. package/src/styles/index.css +4 -0
  35. package/src/styles/pieces.css +70 -0
  36. package/src/utils/animations.js +37 -0
  37. package/{chess.js → src/utils/chess.js} +16 -16
  38. package/src/utils/coordinates.js +62 -0
  39. package/src/utils/cross-browser.js +150 -0
  40. package/src/utils/logger.js +422 -0
  41. package/src/utils/performance.js +311 -0
  42. package/src/utils/validation.js +458 -0
  43. package/.babelrc +0 -4
  44. package/chessboard.bundle.js +0 -3422
  45. package/chessboard.config.js +0 -147
  46. package/chessboard.js +0 -979
  47. package/chessboard.piece.js +0 -115
  48. package/jest.config.js +0 -7
  49. package/rollup.config.js +0 -11
  50. package/test/chessboard.test.js +0 -128
  51. /package/{alepot_theme → assets/themes/alepot}/bb.svg +0 -0
  52. /package/{alepot_theme → assets/themes/alepot}/bw.svg +0 -0
  53. /package/{alepot_theme → assets/themes/alepot}/kb.svg +0 -0
  54. /package/{alepot_theme → assets/themes/alepot}/kw.svg +0 -0
  55. /package/{alepot_theme → assets/themes/alepot}/nb.svg +0 -0
  56. /package/{alepot_theme → assets/themes/alepot}/nw.svg +0 -0
  57. /package/{alepot_theme → assets/themes/alepot}/pb.svg +0 -0
  58. /package/{alepot_theme → assets/themes/alepot}/pw.svg +0 -0
  59. /package/{alepot_theme → assets/themes/alepot}/qb.svg +0 -0
  60. /package/{alepot_theme → assets/themes/alepot}/qw.svg +0 -0
  61. /package/{alepot_theme → assets/themes/alepot}/rb.svg +0 -0
  62. /package/{alepot_theme → assets/themes/alepot}/rw.svg +0 -0
  63. /package/{default_pieces → assets/themes/default}/bb.svg +0 -0
  64. /package/{default_pieces → assets/themes/default}/bw.svg +0 -0
  65. /package/{default_pieces → assets/themes/default}/kb.svg +0 -0
  66. /package/{default_pieces → assets/themes/default}/kw.svg +0 -0
  67. /package/{default_pieces → assets/themes/default}/nb.svg +0 -0
  68. /package/{default_pieces → assets/themes/default}/nw.svg +0 -0
  69. /package/{default_pieces → assets/themes/default}/pb.svg +0 -0
  70. /package/{default_pieces → assets/themes/default}/pw.svg +0 -0
  71. /package/{default_pieces → assets/themes/default}/qb.svg +0 -0
  72. /package/{default_pieces → assets/themes/default}/qw.svg +0 -0
  73. /package/{default_pieces → assets/themes/default}/rb.svg +0 -0
  74. /package/{default_pieces → assets/themes/default}/rw.svg +0 -0
package/chessboard.js DELETED
@@ -1,979 +0,0 @@
1
- import { Chess, validateFen } from './chess.js';
2
- import ChessboardConfig from './chessboard.config.js';
3
- import Square from './chessboard.square.js';
4
- import Piece from './chessboard.piece.js';
5
- import Move from './chessboard.move.js';
6
-
7
- class Chessboard {
8
-
9
- standard_positions = {
10
- 'start': 'start',
11
- 'default': 'rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1',
12
- }
13
-
14
- error_messages = {
15
- 'invalid_position': 'Invalid position - ',
16
- 'invalid_id_div': 'Board id not found - ',
17
- 'invalid_value': 'Invalid value - ',
18
- 'invalid_piece': 'Invalid piece - ',
19
- 'invalid_square': 'Invalid square - ',
20
- 'invalid_fen': 'Invalid fen - ',
21
- 'invalid_orientation': 'Invalid orientation - ',
22
- 'invalid_color': 'Invalid color - ',
23
- 'invalid_mode': 'Invalid mode - ',
24
- 'invalid_dropOffBoard': 'Invalid dropOffBoard - ',
25
- 'invalid_snapbackTime': 'Invalid snapbackTime - ',
26
- 'invalid_snapbackAnimation': 'Invalid snapbackAnimation - ',
27
- 'invalid_fadeTime': 'Invalid fadeTime - ',
28
- 'invalid_fadeAnimation': 'Invalid fadeAnimation - ',
29
- 'invalid_ratio': 'Invalid ratio - ',
30
- 'invalid_piecesPath': 'Invalid piecesPath - ',
31
- 'invalid_onMove': 'Invalid onMove - ',
32
- 'invalid_onMoveEnd': 'Invalid onMoveEnd - ',
33
- 'invalid_onChange': 'Invalid onChange - ',
34
- 'invalid_onDragStart': 'Invalid onDragStart - ',
35
- 'invalid_onDragMove': 'Invalid onDragMove - ',
36
- 'invalid_onDrop': 'Invalid onDrop - ',
37
- 'invalid_onSnapbackEnd': 'Invalid onSnapbackEnd - ',
38
- 'invalid_whiteSquare': 'Invalid whiteSquare - ',
39
- 'invalid_blackSquare': 'Invalid blackSquare - ',
40
- 'invalid_highlight': 'Invalid highlight - ',
41
- 'invalid_selectedSquareWhite': 'Invalid selectedSquareWhite - ',
42
- 'invalid_selectedSquareBlack': 'Invalid selectedSquareBlack - ',
43
- 'invalid_movedSquareWhite': 'Invalid movedSquareWhite - ',
44
- 'invalid_movedSquareBlack': 'Invalid movedSquareBlack - ',
45
- 'invalid_choiceSquare': 'Invalid choiceSquare - ',
46
- 'invalid_coverSquare': 'Invalid coverSquare - ',
47
- 'invalid_hintColor': 'Invalid hintColor - ',
48
- }
49
-
50
- // -------------------
51
- // Initialization
52
- // -------------------
53
- constructor(config) {
54
- this.config = new ChessboardConfig(config);
55
- this.init();
56
- }
57
-
58
- init() {
59
- this.initParams();
60
- this.setGame(this.config.position);
61
- this.buildBoard();
62
- this.buildSquares();
63
- this.addListeners();
64
- this.updateBoardPieces();
65
- }
66
-
67
- initParams() {
68
- this.element = null;
69
- this.squares = {};
70
- this.promoting = false;
71
- this.clicked = null;
72
- this.mosseIndietro = [];
73
- this.clicked = null;
74
- }
75
-
76
- // -------------------
77
- // Board Setup
78
- // -------------------
79
- buildBoard() {
80
- this.element = document.getElementById(this.config.id_div);
81
- if (!this.element) {
82
- throw new Error(this.error_messages['invalid_id_div'] + this.config.id_div);
83
- }
84
- this.resize(this.config.size);
85
- this.element.className = "board";
86
- }
87
-
88
- buildSquares() {
89
-
90
- for (let row = 0; row < 8; row++) {
91
- for (let col = 0; col < 8; col++) {
92
-
93
- let [square_row, square_col] = this.realCoord(row, col);
94
- let square = new Square(square_row, square_col);
95
- this.squares[square.getId()] = square;
96
-
97
- this.element.appendChild(square.element);
98
- }
99
- }
100
- }
101
-
102
- removeBoard() {
103
-
104
- this.element.innerHTML = '';
105
- }
106
-
107
- removeSquares() {
108
- for (const square of Object.values(this.squares)) {
109
- this.element.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.element.offsetWidth === 0) {
120
- size = this.element.offsetHeight;
121
- } else if (this.element.offsetHeight === 0) {
122
- size = this.element.offsetWidth;
123
- } else {
124
- size = Math.min(this.element.offsetWidth, this.element.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
- if (position == 'start') return 'rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1';
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('/') + ' w KQkq - 0 1';;
168
- } else {
169
- throw new Error('Invalid position -' + position);
170
- }
171
- }
172
-
173
- setGame(position, options = undefined) {
174
- const fen = this.convertFen(position);
175
- if (this.game) this.game.load(fen, options);
176
- else this.game = new Chess(fen);
177
- }
178
-
179
- // -------------------
180
- // Piece Functions
181
- // -------------------
182
- getPiecePath(piece) {
183
- if (typeof this.config.piecesPath === 'string')
184
- return this.config.piecesPath + '/' + piece + '.svg';
185
- else if (typeof this.config.piecesPath === 'object')
186
- return this.config.piecesPath[piece];
187
- else if (typeof this.config.piecesPath === 'function')
188
- return this.config.piecesPath(piece);
189
- else
190
- throw new Error(this.error_messages['invalid_piecesPath']);
191
- }
192
-
193
- convertPiece(piece) {
194
- if (piece instanceof Piece) return piece;
195
- if (typeof piece === 'string') {
196
- let [type, color] = piece.split('');
197
- return new Piece(color, type, this.getPiecePath(piece));
198
- }
199
- throw new Error(this.error_messages['invalid_piece'] + piece);
200
- }
201
-
202
- addPieceOnSquare(square, piece, fade = true) {
203
-
204
- square.putPiece(piece);
205
- piece.setDrag(this.dragFunction(square, piece));
206
-
207
- if (fade) piece.fadeIn(
208
- this.config.fadeTime,
209
- this.config.fadeAnimation,
210
- this.transitionTimingFunction
211
- );
212
-
213
- piece.visible();
214
- }
215
-
216
- removePieceFromSquare(square, fade = true) {
217
-
218
- square = this.convertSquare(square);
219
- square.check();
220
-
221
- let piece = square.piece;
222
-
223
- if (!piece) throw Error('Square has no piece to remove.')
224
-
225
- if (fade) piece.fadeOut(
226
- this.config.fadeTime,
227
- this.config.fadeAnimation,
228
- this.transitionTimingFunction);
229
-
230
- square.removePiece();
231
-
232
- return piece;
233
- }
234
-
235
- movePiece(piece, to, duration, callback) {
236
- piece.translate(to, duration, this.transitionTimingFunction, this.config.moveAnimation, callback);
237
- }
238
-
239
- translatePiece(move, removeTo, animate, callback = null) {
240
-
241
- if (removeTo) this.removePieceFromSquare(move.to, false);
242
-
243
- let change_square = () => {
244
- move.from.removePiece();
245
- move.to.putPiece(move.piece);
246
- move.piece.setDrag(this.dragFunction(move.to, move.piece));
247
- if (callback) callback();
248
- }
249
-
250
- let duration = animate ? this.config.moveTime : 0;
251
-
252
- this.movePiece(move.piece, move.to, duration, change_square);
253
-
254
- }
255
-
256
- snapbackPiece(square, animate = this.config.snapbackAnimation) {
257
- let move = new Move(square, square);
258
- this.translatePiece(move, false, animate);
259
- }
260
-
261
- // -------------------
262
- // Board Update Functions
263
- // -------------------
264
- updateBoardPieces(animation = false) {
265
- let { updatedFlags, escapeFlags, movableFlags, pendingTranslations } = this.prepareBoardUpdateData();
266
-
267
- let change = Object.values(updatedFlags).some(flag => !flag);
268
-
269
- this.identifyPieceTranslations(updatedFlags, escapeFlags, movableFlags, pendingTranslations);
270
-
271
- this.executePieceTranslations(pendingTranslations, escapeFlags, animation);
272
-
273
- this.processRemainingPieceUpdates(updatedFlags, animation);
274
-
275
- if (change) this.config.onChange(this.fen());
276
- }
277
-
278
- prepareBoardUpdateData() {
279
- let updatedFlags = {};
280
- let escapeFlags = {};
281
- let movableFlags = {};
282
- let pendingTranslations = [];
283
-
284
- for (let squareId in this.squares) {
285
- let cellPiece = this.squares[squareId].piece;
286
- let cellPieceId = cellPiece ? cellPiece.getId() : null;
287
- updatedFlags[squareId] = this.getGamePieceId(squareId) === cellPieceId;
288
- escapeFlags[squareId] = false;
289
- movableFlags[squareId] = cellPiece ? this.getGamePieceId(squareId) !== cellPieceId : false;
290
- }
291
-
292
- return { updatedFlags, escapeFlags, movableFlags, pendingTranslations };
293
- }
294
-
295
- identifyPieceTranslations(updatedFlags, escapeFlags, movableFlags, pendingTranslations) {
296
- Object.values(this.squares).forEach(targetSquare => {
297
- const newPieceId = this.getGamePieceId(targetSquare.id);
298
- const newPiece = newPieceId && this.convertPiece(newPieceId);
299
- const currentPiece = targetSquare.piece;
300
- const currentPieceId = currentPiece ? currentPiece.getId() : null;
301
-
302
- if (currentPieceId === newPieceId || updatedFlags[targetSquare.id]) return;
303
-
304
- this.evaluateTranslationCandidates(
305
- targetSquare,
306
- newPiece,
307
- currentPiece,
308
- updatedFlags,
309
- escapeFlags,
310
- movableFlags,
311
- pendingTranslations
312
- );
313
- });
314
- }
315
-
316
- evaluateTranslationCandidates(targetSquare, newPiece, oldPiece, updatedFlags, escapeFlags, movableFlags, pendingTranslations) {
317
- if (!newPiece) return;
318
- const newPieceId = newPiece.getId();
319
-
320
- for (const sourceSquare of Object.values(this.squares)) {
321
- if (sourceSquare.id === targetSquare.id || updatedFlags[targetSquare.id]) continue;
322
-
323
- const sourcePiece = sourceSquare.piece;
324
- if (!sourcePiece || !movableFlags[sourceSquare.id] || this.isPiece(newPieceId, sourceSquare.id)) continue;
325
-
326
- if (sourcePiece.id === newPieceId) {
327
- this.handleTranslationMovement(targetSquare, sourceSquare, oldPiece, sourcePiece, updatedFlags, escapeFlags, movableFlags, pendingTranslations);
328
- break;
329
- }
330
- }
331
- }
332
-
333
- handleTranslationMovement(targetSquare, sourceSquare, oldPiece, currentSource, updatedFlags, escapeFlags, movableFlags, pendingTranslations) {
334
- // Verifica il caso specifico "en passant"
335
- let lastMove = this.lastMove();
336
- if (!oldPiece && lastMove && lastMove['captured'] === 'p') {
337
- this.removePieceFromSquare(this.squares[targetSquare.id[0] + sourceSquare.id[1]]);
338
- }
339
-
340
- pendingTranslations.push([currentSource, sourceSquare, targetSquare]);
341
-
342
- if (!this.getGamePieceId(sourceSquare.id)) updatedFlags[sourceSquare.id] = true;
343
-
344
- escapeFlags[sourceSquare.id] = true;
345
- movableFlags[sourceSquare.id] = false;
346
- updatedFlags[targetSquare.id] = true;
347
- }
348
-
349
- executePieceTranslations(pendingTranslations, escapeFlags, animation) {
350
- for (let [_, sourceSquare, targetSquare] of pendingTranslations) {
351
- let removeTarget = !escapeFlags[targetSquare.id] && targetSquare.piece;
352
- let moveObj = new Move(sourceSquare, targetSquare);
353
- this.translatePiece(moveObj, removeTarget, animation);
354
- }
355
- }
356
-
357
- // Gestisce gli aggiornamenti residui per ogni cella che non è ancora stata correttamente aggiornata
358
- processRemainingPieceUpdates(updatedFlags, animation) {
359
- for (const square of Object.values(this.squares)) {
360
- let newPieceId = this.getGamePieceId(square.id);
361
- let newPiece = newPieceId ? this.convertPiece(newPieceId) : null;
362
- let currentPiece = square.piece;
363
- let currentPieceId = currentPiece ? currentPiece.getId() : null;
364
-
365
- if (currentPieceId !== newPieceId && !updatedFlags[square.id]) {
366
- this.updateSinglePiece(square, newPiece, updatedFlags, animation);
367
- }
368
- }
369
- }
370
-
371
- // Aggiorna il pezzo in una cella specifica. Gestisce anche il caso di promozione
372
- updateSinglePiece(square, newPiece, updatedFlags, animation) {
373
- if (!updatedFlags[square.id]) {
374
- let lastMove = this.lastMove();
375
-
376
- if (lastMove?.promotion) {
377
- if (lastMove['to'] === square.id) {
378
-
379
- let move = new Move(this.squares[lastMove['from']], square);
380
- this.translatePiece(move, true, animation
381
- , () => {
382
- move.to.removePiece();
383
- this.addPieceOnSquare(square, newPiece);
384
- });
385
- }
386
- } else {
387
- if (square.piece) this.removePieceFromSquare(square);
388
- if (newPiece) this.addPieceOnSquare(square, newPiece);
389
- }
390
- }
391
- }
392
-
393
- // -------------------
394
- // Event Handlers and Drag
395
- // -------------------
396
- dragFunction(square, piece) {
397
-
398
- return (event) => {
399
-
400
- event.preventDefault();
401
-
402
- if (!this.config.draggable || !piece) return;
403
-
404
- let prec, moved;
405
- let from = square;
406
- let to = square;
407
-
408
- const img = piece.element;
409
-
410
- if (!this.canMove(from)) return;
411
- if (!this.config.clickable) this.clicked = null;
412
- if (this.onClick(from, true, true)) return;
413
-
414
- img.style.position = 'absolute';
415
- img.style.zIndex = 100;
416
-
417
- const moveAt = (pageX, pageY) => {
418
- const halfWidth = img.offsetWidth / 2;
419
- const halfHeight = img.offsetHeight / 2;
420
- img.style.left = `${pageX - halfWidth}px`;
421
- img.style.top = `${pageY - halfHeight}px`;
422
- return true;
423
- };
424
-
425
- const onMouseMove = (event) => {
426
- if (!this.config.onDragStart(square, piece)) return;
427
- if (!moveAt(event.pageX, event.pageY)) return;
428
-
429
- const boardRect = this.element.getBoundingClientRect();
430
- const { offsetWidth: boardWidth, offsetHeight: boardHeight } = this.element;
431
- const x = event.clientX - boardRect.left;
432
- const y = event.clientY - boardRect.top;
433
-
434
- let newTo = null;
435
- if (x >= 0 && x <= boardWidth && y >= 0 && y <= boardHeight) {
436
- const col = Math.floor(x / (boardWidth / 8));
437
- const row = Math.floor(y / (boardHeight / 8));
438
- newTo = this.squares[this.getSquareID(row, col)];
439
- }
440
-
441
- to = newTo;
442
- this.config.onDragMove(from, to, piece);
443
-
444
- if (to !== prec) {
445
- to?.highlight();
446
- prec?.dehighlight();
447
- prec = to;
448
- }
449
- };
450
-
451
- const onMouseUp = () => {
452
- prec?.dehighlight();
453
- document.removeEventListener('mousemove', onMouseMove);
454
- window.removeEventListener('mouseup', onMouseUp);
455
- img.style.zIndex = 20;
456
-
457
- const dropResult = this.config.onDrop(from, to, piece);
458
- const isTrashDrop = !to && (this.config.dropOffBoard === 'trash' || dropResult === 'trash');
459
-
460
- if (isTrashDrop) {
461
- this.allSquares("unmoved");
462
- this.allSquares('removeHint');
463
- from.deselect();
464
- this.remove(from);
465
- } else if (!to || !this.onClick(to, true, true)) {
466
- this.snapbackPiece(from);
467
- if (to !== from) this.config.onSnapbackEnd(from, piece);
468
- }
469
- };
470
-
471
- window.addEventListener('mouseup', onMouseUp, { once: true });
472
- document.addEventListener('mousemove', onMouseMove);
473
- img.addEventListener('mouseup', onMouseUp, { once: true });
474
- }
475
- }
476
-
477
- addListeners() {
478
- for (const square of Object.values(this.squares)) {
479
-
480
- let piece = square.piece;
481
-
482
- square.element.addEventListener("mouseover", (e) => {
483
- if (!this.clicked) this.hintMoves(square);
484
- });
485
- square.element.addEventListener("mouseout", (e) => {
486
- if (!this.clicked) this.dehintMoves(square);
487
- });
488
-
489
- const handleClick = (e) => {
490
- e.stopPropagation();
491
- if (this.config.clickable && (!piece || this.config.onlyLegalMoves)) this.onClick(square)
492
- }
493
-
494
- square.element.addEventListener("mousedown", handleClick);
495
- square.element.addEventListener("touch", handleClick);
496
- }
497
- }
498
-
499
- onClick(square, animation = this.config.moveAnimation, dragged = false) {
500
-
501
- if (this.clicked === square) return false;
502
-
503
- let from = this.clicked;
504
- this.clicked = null;
505
-
506
- let promotion = null
507
-
508
- if (this.promoting) {
509
- if (this.promoting === 'none') from = null
510
- else promotion = this.promoting;
511
-
512
- this.promoting = false;
513
- this.allSquares("removePromotion");
514
- this.allSquares("removeCover");
515
- }
516
-
517
- if (!from) {
518
-
519
- if (this.canMove(square)) {
520
- if (this.config.clickable) {
521
- square.select();
522
- this.hintMoves(square);
523
- }
524
- this.clicked = square;
525
- }
526
-
527
- return false;
528
- }
529
-
530
- let move = new Move(from, square, promotion);
531
-
532
- move.from.deselect();
533
-
534
- if (!move.check()) return false;
535
-
536
- this.allSquares("removeHint");
537
-
538
- if (this.config.onlyLegalMoves && !move.isLegal(this.game)) return false;
539
-
540
- if (!move.hasPromotion() && this.promote(move)) return false;
541
-
542
- if (this.config.onMove(move)) {
543
- this.move(move, animation);
544
- return true;
545
- }
546
-
547
- return false;
548
- }
549
-
550
- // -------------------
551
- // Move Functions
552
- // -------------------
553
- canMove(square) {
554
- if (!square.piece) return false;
555
- if (this.config.movableColors === 'none') return false;
556
- if (this.config.movableColors === 'w' && square.piece.color === 'b') return false;
557
- if (this.config.movableColors === 'b' && square.piece.color === 'w') return false;
558
- if (!this.config.onlyLegalMoves) return true;
559
- return square.piece.color == this.turn();
560
- }
561
-
562
- convertMove(move) {
563
- if (move instanceof Move) return move;
564
- if (typeof move == 'string') {
565
- let fromId = move.slice(0, 2);
566
- let toId = move.slice(2, 4);
567
- let promotion = move.slice(4, 5) ? move.slice(4, 5) : null;
568
- return new Move(this.squares[fromId], this.squares[toId], promotion);
569
- }
570
- throw new Error("Invalid move format");
571
- }
572
-
573
- legalMove(move) {
574
- let legal_moves = this.legalMoves(move.from.id);
575
-
576
- for (let i in legal_moves) {
577
- if (legal_moves[i]['to'] === move.to.id &&
578
- move.promotion == legal_moves[i]['promotion'])
579
- return true;
580
- }
581
-
582
- return false;
583
- }
584
-
585
- legalMoves(from = null, verb = true) {
586
- if (from) return this.game.moves({ square: from, verbose: verb });
587
- return this.game.moves({ verbose: verb });
588
- }
589
-
590
- move(move, animation = true) {
591
- move = this.convertMove(move);
592
- move.check();
593
-
594
- let from = move.from;
595
- let to = move.to;
596
-
597
- if (!this.config.onlyLegalMoves) {
598
- let piece = this.getGamePieceId(from.id);
599
- this.game.remove(from.id);
600
- this.game.remove(to.id);
601
- this.game.put({ type: move.hasPromotion() ? move.promotion : piece[0], color: piece[1] }, to.id);
602
- this.updateBoardPieces(animation);
603
- } else {
604
- this.allSquares("unmoved");
605
-
606
- move = this.game.move({
607
- from: from.id,
608
- to: to.id,
609
- promotion: move.hasPromotion() ? move.promotion : undefined
610
- });
611
-
612
- if (move === null) {
613
- throw new Error("Invalid move: move could not be executed");
614
- }
615
-
616
- this.updateBoardPieces(animation);
617
-
618
- from.moved();
619
- to.moved();
620
- this.allSquares("removeHint");
621
-
622
- this.config.onMoveEnd(move);
623
- }
624
- }
625
-
626
- // -------------------
627
- // Miscellaneous Functions
628
- // -------------------
629
- hint(squareId) {
630
- let square = this.squares[squareId];
631
- if (!this.config.hints || !square) return;
632
- square.putHint(square.piece && square.piece.color !== this.turn());
633
- }
634
-
635
- hintMoves(square) {
636
- if (!this.canMove(square)) return;
637
- let mosse = this.game.moves({ square: square.id, verbose: true });
638
- for (let mossa of mosse) {
639
- if (mossa['to'].length === 2) this.hint(mossa['to']);
640
- }
641
- }
642
-
643
- dehintMoves(square) {
644
- let mosse = this.game.moves({ square: square.id, verbose: true });
645
- for (let mossa of mosse) {
646
- let to = this.squares[mossa['to']];
647
- to.removeHint();
648
- }
649
- }
650
-
651
- allSquares(method) {
652
- for (const square of Object.values(this.squares)) {
653
- square[method]();
654
- this.squares[square.id] = square;
655
- }
656
- }
657
-
658
- promote(move) {
659
-
660
- if (!this.config.onlyLegalMoves) return false;
661
-
662
- let to = move.to;
663
- let from = move.from;
664
- let pezzo = this.game.get(from.id);
665
- let choichable = ['q', 'r', 'b', 'n']
666
-
667
- if (pezzo['type'] !== 'p' || !(to.row === 1 || to.row === 8)) return false;
668
-
669
- for (const square of Object.values(this.squares)) {
670
- let distance = Math.abs(to.row - square.row);
671
-
672
- if (to.col === square.col && distance <= 3) {
673
-
674
- let pieceId = choichable[distance] + pezzo['color'];
675
-
676
- square.putPromotion(
677
- this.getPiecePath(pieceId),
678
- () => {
679
- this.promoting = pieceId[0]
680
- this.clicked = from;
681
- this.onClick(to);
682
- }
683
- );
684
- } else
685
- square.putCover(
686
- () => {
687
- this.promoting = 'none';
688
- this.onClick(square);
689
- });
690
- }
691
-
692
- this.clicked = from.id;
693
-
694
- return true;
695
- }
696
-
697
- transitionTimingFunction(elapsed, duration, type = 'ease') {
698
- let x = elapsed / duration;
699
- switch (type) {
700
- case 'linear':
701
- return x;
702
- case 'ease':
703
- return (x ** 2) * (3 - 2 * x);
704
- case 'ease-in':
705
- return x ** 2;
706
- case 'ease-out':
707
- return -1 * (x - 1) ** 2 + 1;
708
- case 'ease-in-out':
709
- return (x < 0.5) ? 2 * x ** 2 : 4 * x - 2 * x ** 2 - 1;
710
- }
711
- }
712
-
713
- clearSquares() {
714
- this.allSquares('removeHint');
715
- this.allSquares("deselect");
716
- this.allSquares("unmoved");
717
- }
718
-
719
- getGamePieceId(squareId) {
720
- let piece = this.game.get(squareId);
721
- return piece ? piece['type'] + piece['color'] : null;
722
- }
723
-
724
- isPiece(piece, square) { return this.getGamePieceId(square) === piece }
725
-
726
- realCoord(row, col) {
727
- if (this.isWhiteOriented()) row = 7 - row;
728
- else col = 7 - col;
729
- return [row + 1, col + 1];
730
- }
731
-
732
- getSquareID(row, col) {
733
- row = parseInt(row);
734
- col = parseInt(col);
735
- if (this.isWhiteOriented()) {
736
- row = 8 - row;
737
- col = col + 1;
738
- } else {
739
- row = row + 1;
740
- col = 8 - col;
741
- }
742
- let letters = 'abcdefgh';
743
- let letter = letters[col - 1];
744
- return letter + row;
745
- }
746
-
747
- convertSquare(square) {
748
- if (square instanceof Square) return square;
749
- if (typeof square === 'string' && this.squares[square]) return this.squares[square];
750
- throw new Error(this.error_messages['invalid_square'] + square);
751
- }
752
-
753
- // -------------------
754
- // User API and Chess.js Integration
755
- // -------------------
756
- getOrientation() {
757
- return this.config.orientation;
758
- }
759
-
760
- setOrientation(color, animation = true) {
761
- if (['w', 'b'].includes(color)) {
762
- if (color !== this.config.orientation) {
763
- this.flip(animation);
764
- }
765
- } else {
766
- throw new Error(this.error_messages['invalid_orientation'] + color);
767
- }
768
- }
769
-
770
- highlight(squareId) {
771
- let square = this.convertSquare(squareId);
772
- square.check();
773
- square.highlight();
774
- }
775
-
776
- dehighlight(squareId) {
777
- let square = this.convertSquare(squareId);
778
- square.check();
779
- square.dehighlight();
780
- }
781
-
782
- lastMove() {
783
- const moves = this.history({ verbose: true });
784
- return moves[moves.length - 1];
785
- }
786
-
787
- flip() {
788
- this.config.orientation = this.config.orientation === 'w' ? 'b' : 'w';
789
- this.destroy();
790
- this.initParams();
791
- this.build();
792
- }
793
-
794
- build() {
795
- if (this.element) this.destroy();
796
- this.init();
797
- }
798
-
799
- destroy() {
800
- this.removeSquares();
801
- this.removeBoard();
802
- }
803
-
804
- ascii() {
805
- return this.game.ascii();
806
- }
807
-
808
- board() {
809
- let dict = {};
810
- for (let squareId in this.squares) {
811
- let piece = this.getGamePieceId(squareId);
812
- if (piece) dict[squareId] = piece;
813
- }
814
- return dict;
815
- }
816
-
817
- clear(options = {}, animation = true) {
818
- this.game.clear(options);
819
- this.updateBoardPieces(animation);
820
- }
821
-
822
- fen() {
823
- return this.game.fen();
824
- }
825
-
826
- get(squareId) {
827
- const square = this.convertSquare(squareId);
828
- square.check();
829
- return square.piece;
830
- }
831
-
832
- getCastlingRights(color) {
833
- return this.game.getCastlingRights(color);
834
- }
835
-
836
- getComment() {
837
- return this.game.getComment();
838
- }
839
-
840
- getComments() {
841
- return this.game.getComments();
842
- }
843
-
844
- history(options = {}) {
845
- return this.game.history(options);
846
- }
847
-
848
- isCheckmate() {
849
- return this.game.isCheckmate();
850
- }
851
-
852
- isDraw() {
853
- return this.game.isDraw();
854
- }
855
-
856
- isDrawByFiftyMoves() {
857
- return this.game.isDrawByFiftyMoves();
858
- }
859
-
860
- isInsufficientMaterial() {
861
- return this.game.isInsufficientMaterial();
862
- }
863
-
864
- isGameOver() {
865
- return this.game.isGameOver();
866
- }
867
-
868
- isStalemate() {
869
- return this.game.isStalemate();
870
- }
871
-
872
- isThreefoldRepetition() {
873
- return this.game.isThreefoldRepetition();
874
- }
875
-
876
- load(position, options = {}, animation = true) {
877
- this.clearSquares();
878
- this.setGame(position, options);
879
- this.updateBoardPieces(animation);
880
- }
881
-
882
- loadPgn(pgn, options = {}, animation = true) {
883
- this.clearSquares();
884
- this.game.loadPgn(pgn, options);
885
- this.updateBoardPieces();
886
- }
887
-
888
- moveNumber() {
889
- return this.game.moveNumber();
890
- }
891
-
892
- moves(options = {}) {
893
- return this.game.moves(options);
894
- }
895
-
896
- pgn(options = {}) {
897
- return this.game.pgn(options);
898
- }
899
-
900
- put(pieceId, squareId, animation = true) {
901
- const [type, color] = pieceId.split('');
902
- const success = this.game.put({ type: type, color: color }, squareId);
903
- if (success) this.updateBoardPieces(animation);
904
- return success;
905
- }
906
-
907
- remove(squareId, animation = true) {
908
- const removedPiece = this.game.remove(squareId);
909
- this.updateBoardPieces(animation);
910
- return removedPiece;
911
- }
912
-
913
- removeComment() {
914
- return this.game.removeComment();
915
- }
916
-
917
- removeComments() {
918
- return this.game.removeComments();
919
- }
920
-
921
- removeHeader(field) {
922
- return this.game.removeHeader(field);
923
- }
924
-
925
- reset(animation = true) {
926
- this.game.reset();
927
- this.updateBoardPieces(animation);
928
- }
929
-
930
- setCastlingRights(color, rights) {
931
- return this.game.setCastlingRights(color, rights);
932
- }
933
-
934
- setComment(comment) {
935
- this.game.setComment(comment);
936
- }
937
-
938
- setHeader(key, value) {
939
- return this.game.setHeader(key, value);
940
- }
941
-
942
- squareColor(squareId) {
943
- return this.game.squareColor(squareId);
944
- }
945
-
946
- turn() {
947
- return this.game.turn();
948
- }
949
-
950
- undo() {
951
- const move = this.game.undo();
952
- if (move) this.updateBoardPieces();
953
- return move;
954
- }
955
-
956
- validateFen(fen) {
957
- return validateFen(fen);
958
- }
959
-
960
- // -------------------
961
- // Other Utility Functions
962
- // -------------------
963
- chageFenTurn(fen, color) {
964
- let parts = fen.split(' ');
965
- parts[1] = color;
966
- return parts.join(' ');
967
- }
968
-
969
- changeFenColor(fen) {
970
- let parts = fen.split(' ');
971
- parts[1] = parts[1] === 'w' ? 'b' : 'w';
972
- return parts.join(' ');
973
- }
974
-
975
- isWhiteOriented() { return this.config.orientation === 'w' }
976
-
977
- }
978
-
979
- export default Chessboard;