@alepot55/chessboardjs 1.1.0 → 2.0.3

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_min.js DELETED
@@ -1,1220 +0,0 @@
1
- const DEFAULT_POSITION_WHITE = 'rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1'
2
- const SLOW_ANIMATION = 600;
3
- const FAST_ANIMATION = 150;
4
-
5
- class ChessboardConfig {
6
-
7
- constructor(settings) {
8
-
9
- let defaults = {
10
-
11
- // ---------------------- General
12
- id_div: 'board',
13
- position: 'start',
14
- orientation: 'w',
15
- mode: 'normal',
16
- size: 'auto',
17
-
18
- // ---------------------- Moves
19
- draggable: true,
20
- hints: true,
21
- clickable: true,
22
- movableColors: 'both',
23
- moveHighlight: true,
24
- overHighlight: true,
25
- moveAnimation: 'ease',
26
- moveTime: 'fast',
27
-
28
- // ---------------------- Snapback
29
- dropOffBoard: 'snapback',
30
- snapbackTime: 'fast',
31
- snapbackAnimation: 'ease',
32
-
33
- // ---------------------- Fade
34
- fadeTime: 'fast',
35
- fadeAnimation: 'ease',
36
-
37
- // ---------------------- Pieces
38
- ratio: 0.9,
39
- piecesPath: 'https://cdn.jsdelivr.net/npm/@alepot55/chessboardjs/default_pieces',
40
-
41
- // ---------------------- Events
42
- onMove: () => true,
43
- onMoveEnd: () => true,
44
- onChange: () => true,
45
- onDragStart: () => true,
46
- onDragMove: () => true,
47
- onDrop: () => true,
48
- onSnapbackEnd: () => true,
49
-
50
- // ---------------------- Colors
51
- whiteSquare: '#f0d9b5',
52
- blackSquare: '#b58863',
53
- highlight: 'yellow',
54
- selectedSquareWhite: '#ababaa',
55
- selectedSquareBlack: '#ababaa',
56
- movedSquareWhite: '#f1f1a0',
57
- movedSquareBlack: '#e9e981',
58
- choiceSquare: 'white',
59
- coverSquare: 'black',
60
- hintColor: '#ababaa'
61
- };
62
-
63
- // ---------------------- General
64
-
65
- // id_div: string
66
- this.id_div = settings.id_div === undefined ? defaults.id_div : settings.id_div;
67
-
68
- // position: 'start', 'fen', {a1: 'wp', b2: 'bp', ...}, 'default'
69
- this.position = settings.position === undefined ? defaults.position : settings.position;
70
-
71
- // orientation: 'w', 'b'
72
- this.orientation = settings.orientation === undefined ? defaults.orientation : settings.orientation;
73
-
74
- // mode: 'normal', 'creative'
75
- this.mode = settings.mode === undefined ? defaults.mode : settings.mode;
76
-
77
- // deaggable: true, false
78
- this.draggable = settings.draggable === undefined ? defaults.draggable : settings.draggable;
79
-
80
- // dropOffBoard: 'snapback', 'trash'
81
- this.dropOffBoard = settings.dropOffBoard == undefined ? defaults.dropOffBoard : settings.dropOffBoard;
82
-
83
- // hints: true, false. se settings non contiene hints, allora hints = true
84
- this.hints = settings.hints === undefined ? defaults.hints : settings.hints;
85
-
86
- // clickable: true, false
87
- this.clickable = settings.clickable === undefined ? defaults.clickable : settings.clickable;
88
-
89
- // size: integer or 'auto'
90
- this.size = settings.size === undefined ? defaults.size : settings.size;
91
-
92
- // ---------------------- Moves
93
-
94
- // movableColors: 'white', 'black', 'both', 'none'
95
- this.movableColors = settings.movableColors === undefined ? defaults.movableColors : settings.movableColors;
96
-
97
- // moveHighlight: true, false
98
- this.moveHighlight = settings.moveHighlight === undefined ? defaults.moveHighlight : settings.moveHighlight;
99
-
100
- // overHighlight: true, false
101
- this.overHighlight = settings.overHighlight === undefined ? defaults.overHighlight : settings.overHighlight;
102
-
103
- // moveAnimation: 'linear', 'ease', 'ease-in', 'ease-out', 'ease-in-out', 'none'
104
- this.moveAnimation = settings.moveAnimation === undefined ? defaults.moveAnimation : settings.moveAnimation;
105
-
106
- // moveTime: integer, 'slow', 'fast'
107
- this.moveTime = settings.moveTime === undefined ? defaults.moveTime : settings.moveTime;
108
-
109
- // ---------------------- Snapback
110
-
111
- // snapbackTime: integer, 'slow', 'fast'f
112
- this.snapbackTime = settings.snapbackTime === undefined ? defaults.snapbackTime : settings.snapbackTime;
113
-
114
- // snapbackAnimation: 'linear', 'ease', 'ease-in', 'ease-out', 'ease-in-out', 'none'
115
- this.snapbackAnimation = settings.snapbackAnimation === undefined ? defaults.snapbackAnimation : settings.snapbackAnimation;
116
-
117
- // ---------------------- Fade
118
-
119
- // fadeTime: integer, 'slow', 'fast'
120
- this.fadeTime = settings.fadeTime === undefined ? defaults.fadeTime : settings.fadeTime;
121
-
122
- // fadeAnimation: 'linear', 'ease', 'ease-in', 'ease-out', 'ease-in-out', 'none'
123
- this.fadeAnimation = settings.fadeAnimation === undefined ? defaults.fadeAnimation : settings.fadeAnimation;
124
-
125
- // ---------------------- Pieces
126
-
127
- // ratio: integer
128
- settings.ratio === undefined ? this.setCSSProperty('pieceRatio', defaults.ratio) : this.setCSSProperty('pieceRatio', settings.ratio);
129
-
130
- // piecesPath: string
131
- this.piecesPath = settings.piecesPath === undefined ? defaults.piecesPath : settings.piecesPath;
132
-
133
-
134
- // ---------------------- Events
135
-
136
- // onMove: function(move)
137
- this.onMove = settings.onMove === undefined ? defaults.onMove : settings.onMove;
138
-
139
- // onMoveEnd: function(move)
140
- this.onMoveEnd = settings.onMoveEnd === undefined ? defaults.onMoveEnd : settings.onMoveEnd;
141
-
142
- // onChange: function(fen)
143
- this.onChange = settings.onChange === undefined ? defaults.onChange : settings.onChange;
144
-
145
- // onDragStart: function(from, piece)
146
- this.onDragStart = settings.onDragStart === undefined ? defaults.onDragStart : settings.onDragStart;
147
-
148
- // onDragMove: function(from, to, piece)
149
- this.onDragMove = settings.onDragMove === undefined ? defaults.onDragMove : settings.onDragMove;
150
-
151
- // onDrop: function(from, to, piece)
152
- this.onDrop = settings.onDrop === undefined ? defaults.onDrop : settings.onDrop;
153
-
154
- // onSnapbackEnd: function(from, piece)
155
- this.onSnapbackEnd = settings.onSnapbackEnd === undefined ? defaults.onSnapbackEnd : settings.onSnapbackEnd;
156
-
157
- // ---------------------- Colors
158
-
159
- // whiteSquare: string
160
- settings.whiteSquare === undefined ? this.setCSSProperty('whiteSquare', defaults.whiteSquare) : this.setCSSProperty('whiteSquare', settings.whiteSquare);
161
-
162
- // blackSquare: string
163
- settings.blackSquare === undefined ? this.setCSSProperty('blackSquare', defaults.blackSquare) : this.setCSSProperty('blackSquare', settings.blackSquare);
164
-
165
- // highlight: string
166
- settings.highlight === undefined ? this.setCSSProperty('highlightSquare', defaults.highlight) : this.setCSSProperty('highlightSquare', settings.highlight);
167
-
168
- // selectedSquareWhite: string
169
- settings.selectedSquareWhite === undefined ? this.setCSSProperty('selectedSquareWhite', defaults.selectedSquareWhite) : this.setCSSProperty('selectedSquareWhite', settings.selectedSquareWhite);
170
-
171
- // selectedSquareBlack: string
172
- settings.selectedSquareBlack === undefined ? this.setCSSProperty('selectedSquareBlack', defaults.selectedSquareBlack) : this.setCSSProperty('selectedSquareBlack', settings.selectedSquareBlack);
173
-
174
- // movedSquareWhite: string
175
- settings.movedSquareWhite === undefined ? this.setCSSProperty('movedSquareWhite', defaults.movedSquareWhite) : this.setCSSProperty('movedSquareWhite', settings.movedSquareWhite);
176
-
177
- // movedSquareBlack: string
178
- settings.movedSquareBlack === undefined ? this.setCSSProperty('movedSquareBlack', defaults.movedSquareBlack) : this.setCSSProperty('movedSquareBlack', settings.movedSquareBlack);
179
-
180
- // choiceSquare: string
181
- settings.choiceSquare === undefined ? this.setCSSProperty('choiceSquare', defaults.choiceSquare) : this.setCSSProperty('choiceSquare', settings.choiceSquare);
182
-
183
- // coverSquare: string
184
- settings.coverSquare === undefined ? this.setCSSProperty('coverSquare', defaults.coverSquare) : this.setCSSProperty('coverSquare', settings.coverSquare);
185
-
186
- // hintColor: string
187
- settings.hintColor === undefined ? this.setCSSProperty('hintColor', defaults.hintColor) : this.setCSSProperty('hintColor', settings.hintColor);
188
-
189
- // Configure modes
190
-
191
- if (this.mode === 'creative') {
192
- this.onlyLegalMoves = false;
193
- this.hints = false;
194
- } else if (this.mode === 'normal') {
195
- this.onlyLegalMoves = true;
196
- }
197
-
198
- return this;
199
- }
200
-
201
- setCSSProperty(property, value) {
202
- document.documentElement.style.setProperty('--' + property, value);
203
- }
204
-
205
- setOrientation(orientation) {
206
- this.orientation = orientation;
207
- return this;
208
- }
209
- }
210
-
211
- class Chessboard {
212
-
213
- constructor(config) {
214
-
215
- this.config = new ChessboardConfig(config);
216
-
217
- this.pezzi = {};
218
- this.pieces = {};
219
- this.celle = {};
220
- this.squares = {};
221
- this.buildGame(this.config.position);
222
- this.initParams();
223
- this.buildBoard();
224
- this.updatePosition();
225
- }
226
-
227
- // Build
228
-
229
- buildGame(position) {
230
- if (position === 'start') {
231
- this.game = new Chess();
232
- } else if (position === 'default') {
233
- this.game = new Chess(DEFAULT_POSITION_WHITE);
234
- } else if (typeof position === 'string') {
235
- this.game = new Chess(position);
236
- } else if (typeof position === 'object') {
237
- let game = new Chess('start');
238
- for (let square in position) {
239
- game.put({ type: position[square][0], color: position[square][1] }, square);
240
- }
241
- this.game = game;
242
- } else {
243
- throw new Error('Invalid position - ' + position + ' - must be a fen string, "start", "default" or a dictionary of pieces, like {a1: "wK", b2: "bQ", ...}');
244
- }
245
- }
246
-
247
- buildBoard() {
248
- this.board = document.getElementById(this.config.id_div);
249
- if (!this.board) {
250
- throw new Error('Board id not found - ' + this.config.id_div + ' - must be a valid id of a div element');
251
- }
252
- this.resize(this.config.size);
253
- this.board.className = "board";
254
- this.buildSquares();
255
- }
256
-
257
- buildSquares() {
258
- this.squares = {};
259
- this.lastSquare = null;
260
- this.celle = {};
261
- this.pezzi = {};
262
- this.pieces = {};
263
- this.mosseIndietro = [];
264
-
265
-
266
- for (let row = 0; row < 8; row++) {
267
-
268
- this.squares[row] = {};
269
-
270
- for (let col = 0; col < 8; col++) {
271
-
272
- // Imposta l'id della cella e crea un nuovo elemento div
273
- let id = this.getSquareID(row, col)
274
- let square = document.createElement("div");
275
-
276
- this.celle[id] = square;
277
- this.squares[row][col] = square;
278
- square.id = id;
279
- this.resetSquare(id);
280
-
281
- this.board.appendChild(square);
282
- }
283
- }
284
-
285
- this.addListeners();
286
- }
287
-
288
- initParams() {
289
- this.promoting = false;
290
- this.lastSquare = null;
291
- this.history = [];
292
- this.mosseIndietro = [];
293
- this.lastSquare = null;
294
- }
295
-
296
- resize(value) {
297
- if (value === 'auto') {
298
- let size;
299
- if (this.board.offsetWidth === 0) {
300
- size = this.board.offsetHeight;
301
- } else if (this.board.offsetHeight === 0) {
302
- size = this.board.offsetWidth;
303
- } else {
304
- size = Math.min(this.board.offsetWidth, this.board.offsetHeight);
305
- }
306
- this.resize(size);
307
- } else if (typeof value !== 'number') {
308
- throw new Error('Invalid value - ' + value + ' - must be a number or "auto"');
309
- } else {
310
- document.documentElement.style.setProperty('--dimBoard', value + 'px');
311
- this.updatePosition();
312
- }
313
- }
314
-
315
- destroy() {
316
- if (!this.board) throw new Error('Board not found');
317
- this.board.innerHTML = '';
318
- this.board.className = '';
319
- }
320
-
321
-
322
- // Pieces
323
-
324
- checkPiece(piece) {
325
- if (['p', 'r', 'n', 'b', 'q', 'k'].indexOf(piece[0]) === -1 || ['w', 'b'].indexOf(piece[1]) === -1) throw new Error('Invalid piece - ' + piece + ' - must be a valid piece like "pw" or "kb"');
326
- }
327
-
328
- getPiecePath(piece) {
329
- if (typeof this.config.piecesPath === 'string') return this.config.piecesPath + '/' + piece + '.svg';
330
- else return this.config.piecesPath(piece);
331
- }
332
-
333
- piece(square) {
334
- this.checkSquare(square);
335
- let piece = this.game.get(square);
336
- return piece ? piece['type'] + piece['color'] : null;
337
- }
338
-
339
- colorPiece(square) {
340
- let piece = this.piece(square);
341
- return piece ? piece[1] : null;
342
- }
343
-
344
- traslation(elem, from, to, duration) {
345
-
346
- let piece = elem.src.split('/').pop().split('.')[0];
347
-
348
- if (duration === 'none' || duration === 0) {
349
- this.removePiece(from, piece, false);
350
- this.insert(to, piece, false);
351
- return;
352
- }
353
- else if (duration === 'slow') duration = SLOW_ANIMATION;
354
- else if (duration === 'fast') duration = FAST_ANIMATION;
355
-
356
- let startX, startY, endX, endY;
357
-
358
- if (from) {
359
- startX = this.celle[from].getBoundingClientRect().left;
360
- startY = this.celle[from].getBoundingClientRect().top;
361
- } else {
362
- startX = elem.getBoundingClientRect().left - 4;
363
- startY = elem.getBoundingClientRect().top - 4;
364
- }
365
-
366
- endX = this.celle[to].getBoundingClientRect().left;
367
- endY = this.celle[to].getBoundingClientRect().top;
368
-
369
-
370
- let x = endX - startX;
371
- let y = endY - startY;
372
- let startTime;
373
- let board = this;
374
-
375
- function translate(currentTime) {
376
- if (!startTime) {
377
- startTime = currentTime;
378
- }
379
-
380
- let timeElapsed = currentTime - startTime;
381
- let t = timeElapsed / duration;
382
- let progress = board.transitionTimingFunction(t, board.config.moveAnimation);
383
- elem.style.transform = 'translate(' + (x * progress) + 'px, ' + (y * progress) + 'px)';
384
-
385
- if (t < 1) {
386
- requestAnimationFrame(translate);
387
- } else {
388
- if (from) board.removePiece(from, piece, false);
389
- if (to) board.insert(to, board.piece(to), false);
390
- }
391
- }
392
-
393
- requestAnimationFrame(translate);
394
- }
395
-
396
- translatePiece(piece, from, to, removeTo, animate) {
397
-
398
- if (!animate) {
399
- this.removePiece(from, piece, false);
400
- this.insert(to, piece, false);
401
- return;
402
- };
403
-
404
- let elem = this.pieces[(piece, from)]['img'];
405
-
406
- if (removeTo) this.removePiece(to);
407
-
408
- return this.traslation(elem, from, to, this.config.moveTime);
409
- }
410
-
411
- snapbackPiece(square, piece, animate) {
412
-
413
- if (!animate || this.config.snapbackAnimation === 'none' || this.config.snapbackTime === 0) {
414
- this.removePiece(square, piece, false);
415
- this.insert(square, piece, false);
416
- return;
417
- }
418
-
419
- let elem = this.pieces[(piece, square)]['img'];
420
- this.traslation(elem, null, square, this.config.snapbackTime);
421
- }
422
-
423
- fadeInPiece(square) {
424
-
425
- let duration = this.config.fadeTime;
426
- if (duration === 'slow') duration = SLOW_ANIMATION;
427
- else if (duration === 'fast') duration = FAST_ANIMATION;
428
-
429
- let elem = this.pezzi[square]['img'];
430
-
431
- let startTime;
432
- let board = this;
433
-
434
- function fadeIn(currentTime) {
435
- if (!startTime) {
436
- startTime = currentTime;
437
- }
438
- let timeElapsed = currentTime - startTime;
439
- let t = timeElapsed / duration;
440
- let progress = board.transitionTimingFunction(t, board.config.fadeAnimation);
441
- elem.style.opacity = progress;
442
-
443
- if (t < 1) {
444
- requestAnimationFrame(fadeIn);
445
- }
446
- }
447
-
448
- requestAnimationFrame(fadeIn);
449
- }
450
-
451
- fadeOutPiece(square, img, remove, animate) {
452
-
453
- let duration = this.config.fadeTime;
454
- if (duration === 'slow') duration = SLOW_ANIMATION;
455
- else if (duration === 'fast') duration = FAST_ANIMATION;
456
-
457
- if (!animate) {
458
- if (remove) this.celle[square].removeChild(img);
459
- else img.style.opacity = 0;
460
- return;
461
- }
462
-
463
- let startTime;
464
- let board = this;
465
-
466
- function fadeOut(currentTime) {
467
- if (!startTime) {
468
- startTime = currentTime;
469
- }
470
- let timeElapsed = currentTime - startTime;
471
- let t = timeElapsed / duration;
472
- let progress = board.transitionTimingFunction(t, board.config.fadeAnimation);
473
- img.style.opacity = 1 - progress;
474
-
475
- if (t < 1) {
476
- requestAnimationFrame(fadeOut);
477
- } else {
478
- if (remove) board.celle[square].removeChild(img);
479
- }
480
- }
481
-
482
- requestAnimationFrame(fadeOut);
483
- }
484
-
485
- removePiece(square, piece, fade = true) {
486
-
487
- if (!this.pezzi[square]) return null;
488
- piece = piece ? piece : this.pezzi[square]['piece'];
489
- if (this.pezzi[square]['piece'] !== piece) return null;
490
-
491
- if (fade) this.fadeOutPiece(square, this.pezzi[square]['img']);
492
- else this.celle[square].removeChild(this.pezzi[square]['img']);
493
-
494
- this.pezzi[square] = null;
495
- this.pieces[(piece, square)] = null;
496
-
497
- return piece;
498
- }
499
-
500
- insert(square, piece, fade = this.config.fadeAnimation) {
501
-
502
- if (fade === 'none' || fade === 0) fade = false;
503
-
504
- this.checkPiece(piece);
505
- this.checkSquare(square);
506
-
507
- if (!piece) return;
508
- this.removePiece(square, null, false);
509
-
510
- let img = document.createElement("img");
511
- img.className = "piece";
512
- img.src = this.getPiecePath(piece);
513
- img.style.opacity = fade ? 0 : 1;
514
-
515
- let board = this;
516
- img.onmousedown = function (event) {
517
-
518
- if (!board.config.draggable) return;
519
-
520
- let recent;
521
- let from = square;
522
- let to = square;
523
- let moved = false;
524
-
525
- if (!board.canMove(from)) return;
526
-
527
- if (!board.config.clickable) board.lastSquare = null;
528
- if (board.onClick(square)) return;
529
-
530
- img.style.position = 'absolute';
531
- img.style.zIndex = 15;
532
-
533
- // Function to move the piece with the mouse pointer
534
- function moveAt(pageX, pageY) {
535
- if (!moved && !board.config.onDragStart(from, piece)) return;
536
- moved = true;
537
- img.style.left = pageX - img.offsetWidth / 2 + 'px';
538
- img.style.top = pageY - img.offsetHeight / 2 + 'px';
539
- return true;
540
- }
541
-
542
- function onMouseMove(event) {
543
-
544
- // Bug fix for spamming the mousemove event
545
- if (!piece) return;
546
-
547
- if (!moveAt(event.pageX, event.pageY)) return;
548
-
549
- // Find the square where the mouse is
550
- let x = event.clientX - board.board.getBoundingClientRect().left;
551
- let y = event.clientY - board.board.getBoundingClientRect().top;
552
-
553
- let col = Math.floor(x / (board.board.offsetWidth / 8));
554
- let row = Math.floor(y / (board.board.offsetHeight / 8));
555
- if (x < 0 || x > board.board.offsetWidth || y < 0 || y > board.board.offsetHeight) to = null;
556
- else to = board.getSquareID(row, col);
557
- board.config.onDragMove(from, to, piece);
558
-
559
- if (to !== recent) {
560
- board.highlight(to);
561
- board.dehighlight(recent);
562
- recent = to;
563
- }
564
- }
565
- document.addEventListener('mousemove', onMouseMove);
566
-
567
- // Drop the piece and remove the event listener
568
- img.onmouseup = function () {
569
- board.dehighlight(recent);
570
- document.removeEventListener('mousemove', onMouseMove);
571
- img.onmouseup = null;
572
- let drop = board.config.onDrop(from, to, piece);
573
-
574
- if ((board.config.dropOffBoard === 'trash' || drop === 'trash') && !to) {
575
- board.unmoveAllSquares();
576
- board.dehintAllSquares();
577
- board.deselect(from);
578
- board.remove(from);
579
- } else if (moved && (!board.onClick(to, false) || drop === 'snapback')) {
580
- board.snapbackPiece(from, piece, !board.promoting);
581
- board.config.onSnapbackEnd(from, piece);
582
- }
583
- };
584
-
585
- };
586
-
587
- // Prevent the image from being dragged
588
- img.ondragstart = function () {
589
- return false;
590
- };
591
-
592
- this.pezzi[square] = { 'img': img, 'piece': piece };
593
- this.pieces[(piece, square)] = { 'img': img };
594
- this.celle[square].appendChild(img);
595
-
596
- if (fade) this.fadeInPiece(square);
597
- else img.style.opacity = 1;
598
- return img;
599
- }
600
-
601
- updatePieces(animation) {
602
-
603
- let ok = {};
604
- let escaping = {};
605
- let canEscape = {};
606
- let toTranslate = [];
607
-
608
- for (let square in this.celle) {
609
- ok[square] = false;
610
- escaping[square] = false;
611
- canEscape[square] = this.pezzi[square] && this.piece(square) !== this.pezzi[square]['piece'];
612
- }
613
-
614
-
615
- for (let square in this.celle) {
616
-
617
- let pieceNew = this.piece(square);
618
- let pieceOld = this.pezzi[square] ? this.pezzi[square]['piece'] : null;
619
-
620
- if (pieceOld !== pieceNew && !ok[square]) {
621
-
622
-
623
- for (let from in this.pezzi) {
624
-
625
- let coming = this.pezzi[from] ? this.pezzi[from]['piece'] : null;
626
-
627
- if (coming && canEscape[from] && !ok[square] && from !== square && coming === pieceNew && !this.isPiece(pieceNew, from)) {
628
-
629
- // check for en passant
630
- let lastMove = this.lastMove();
631
- if (!pieceOld && lastMove && lastMove['captured'] === 'p') {
632
- let captured = 'p' + (lastMove['color'] === 'w' ? 'b' : 'w');
633
- this.removePiece(square[0] + from[1], captured);
634
- }
635
-
636
- toTranslate.push([coming, from, square]);
637
-
638
- if (!this.piece(from)) ok[from] = true;
639
- escaping[from] = true;
640
- canEscape[from] = false;
641
-
642
- ok[square] = true;
643
-
644
- break;
645
- }
646
- }
647
- }
648
- }
649
-
650
- for (let [piece, from, to] of toTranslate) {
651
- this.translatePiece(piece, from, to, !escaping[to], animation);
652
- }
653
-
654
- for (let square in this.celle) {
655
-
656
- let pieceNew = this.piece(square);
657
- let pieceOld = this.pezzi[square] ? this.pezzi[square]['piece'] : null;
658
-
659
- if (pieceOld !== pieceNew && !ok[square]) {
660
-
661
- if (!ok[square]) {
662
- // check for promotion
663
- let lastMove = this.lastMove();
664
- if (lastMove && lastMove['promotion']) {
665
- if (lastMove['to'] === square) {
666
- let piece = lastMove['promotion'] + lastMove['color'];
667
- this.translatePiece(piece, lastMove['from'], square, true, animation);
668
- ok[lastMove['from']] = true;
669
- }
670
- } else {
671
- this.removePiece(square);
672
- if (pieceNew) this.insert(square, pieceNew);
673
- }
674
- }
675
- }
676
- }
677
-
678
- this.config.onChange(this.game.fen());
679
- }
680
-
681
- opponentPiece(square) {
682
- let piece = this.piece(square);
683
- return piece && piece[1] !== this.config.orientation;
684
- }
685
-
686
- playerPiece(square) {
687
- let piece = this.piece(square);
688
- return piece && piece[1] === this.config.orientation;
689
- }
690
-
691
- isPiece(piece, square) {
692
- return this.piece(square) === piece;
693
- }
694
-
695
- remove(square, animation = true) {
696
- this.checkSquare(square);
697
- this.game.remove(square);
698
- this.removePiece(square, null, animation);
699
- }
700
-
701
-
702
- // Listeners
703
-
704
- addListeners() {
705
- if (this.mosseIndietro.length > 0) return;
706
- for (let square in this.celle) {
707
- let elem = this.celle[square];
708
- elem.addEventListener("mouseover", () => {
709
- if (!this.lastSquare) this.hintMoves(elem.id);
710
- });
711
- elem.addEventListener("mouseout", () => {
712
- if (!this.lastSquare) this.dehintMoves(elem.id);
713
- });
714
- elem.addEventListener("click", () => {
715
- if (this.config.clickable && (!this.pezzi[elem.id] || this.config.onlyLegalMoves)) this.onClick(elem.id)
716
- });
717
- elem.addEventListener("touch", () => {
718
- if (this.config.clickable) this.onClick(elem.id)
719
- });
720
- }
721
- }
722
-
723
- onClick(square, animation = this.config.moveAnimation) {
724
-
725
- if (!square || square === this.lastSquare) return;
726
-
727
- if (animation === 'none') animation = false;
728
-
729
- if (this.promoting) {
730
- this.depromoteAllSquares();
731
- this.removeAllCovers();
732
- this.promoting = false;
733
- if (square.length === 2) this.lastSquare = null;
734
- }
735
-
736
- let from = this.lastSquare;
737
- this.lastSquare = null;
738
- let move = from + square;
739
-
740
- if (from) {
741
- this.deselect(from);
742
- this.dehintAllSquares();
743
- } else if (!this.canMove(square)) return;
744
-
745
-
746
- if (from && this.canMove(from) && (!this.canMove(square) || !this.config.onlyLegalMoves)) {
747
-
748
- if (this.config.onlyLegalMoves && !this.legalMove(move)) return;
749
- if (move.length == 4 && this.promote(move)) return;
750
-
751
- if (this.config.onMove(move)) this.move(move, animation);
752
- else return;
753
-
754
- return true;
755
-
756
- } else if (this.canMove(square)) {
757
-
758
- this.select(square);
759
- this.hintMoves(square);
760
- this.lastSquare = square;
761
- }
762
- }
763
-
764
- // Hint
765
-
766
- hint(square) {
767
- this.checkSquare(square);
768
- if (!this.config.hints || !this.celle[square]) return;
769
-
770
- let hint = document.createElement("div");
771
- hint.className = "hint";
772
-
773
- if (this.colorPiece(square) && this.colorPiece(square) !== this.turn()) hint.className += " catchable";
774
-
775
- this.celle[square].appendChild(hint);
776
-
777
- }
778
-
779
- hintMoves(square) {
780
- if (!this.canMove(square)) return;
781
- let mosse = this.game.moves({ square: square, verbose: true });
782
- for (let mossa of mosse) {
783
- if (mossa['to'].length === 2) this.hint(mossa['to']);
784
- }
785
- }
786
-
787
- dehintMoves(square) {
788
- let mosse = this.game.moves({ square: square, verbose: true });
789
- for (let mossa of mosse) {
790
- if (mossa['to'].length === 2) this.dehint(mossa['to']);
791
- }
792
- }
793
-
794
- dehint(square) {
795
- if (square.length !== 2) return;
796
- if (this.config.hints) {
797
- let cella = this.celle[square];
798
- if (!cella) return;
799
- let figli = cella.childNodes;
800
-
801
- for (let i = figli.length - 1; i >= 0; i--) {
802
- if (figli[i].className.includes('hint')) {
803
- cella.removeChild(figli[i]);
804
- }
805
- }
806
- }
807
- }
808
-
809
- dehintAllSquares() {
810
- for (let casella in this.celle) {
811
- this.dehint(casella);
812
- }
813
- }
814
-
815
- // Select
816
-
817
- select(square) {
818
- this.checkSquare(square);
819
- if (!this.config.clickable) return;
820
- let elem = this.celle[square];
821
- if (elem.className.includes('selectedSquareWhite') || elem.className.includes('selectedSquareBlack')) return;
822
- if (this.isWhiteSquare(square)) elem.className += ' selectedSquareWhite';
823
- else elem.className += ' selectedSquareBlack';
824
- }
825
-
826
- deselect(square) {
827
- this.checkSquare(square);
828
- let elem = this.celle[square];
829
- if (this.isWhiteSquare(square)) elem.className = elem.className.replace(' selectedSquareWhite', '');
830
- else elem.className = elem.className.replace(' selectedSquareBlack', '');
831
- }
832
-
833
- deselectAllSquares() {
834
- for (let casella in this.celle) {
835
- this.deselect(casella);
836
- }
837
- }
838
-
839
- // Moves
840
-
841
- checkMove(move) {
842
- if (move.length < 4 || move.length > 5) throw new Error('Invalid move - ' + move + ' - must be a valid move like "e2e4" or "e7e8q"');
843
- let from = move.slice(0, 2);
844
- let to = move.slice(2, 4);
845
- let prom = move.length === 5 ? move[4] : null;
846
- this.checkSquare(from);
847
- this.checkSquare(to);
848
- if (prom && ['q', 'r', 'n', 'b'].indexOf(prom) === -1) throw new Error('Invalid promotion - ' + prom + ' - must be a valid piece like "q", "r", "n" or "b"');
849
- }
850
-
851
- canMove(square) {
852
- if (!this.piece(square)) return false;
853
- if (this.config.movableColors === 'none') return false;
854
- if (this.config.movableColors === 'w' && this.colorPiece(square) === 'b') return false;
855
- if (this.config.movableColors === 'b' && this.colorPiece(square) === 'w') return false;
856
- if (!this.config.onlyLegalMoves) return true;
857
- if (this.colorPiece(square) !== this.turn()) return false;
858
- return true;
859
- }
860
-
861
- move(move, animation) {
862
-
863
- if (!this.canMove(move.slice(0, 2))) return false;
864
-
865
- this.checkMove(move);
866
-
867
- if (!this.config.onlyLegalMoves) {
868
- let piece = this.piece(move.slice(0, 2));
869
- this.game.remove(move.slice(0, 2));
870
- this.game.remove(move.slice(2, 4));
871
- this.game.put({ type: move[4] ? move[4] : piece[0], color: piece[1] }, move.slice(2, 4));
872
- return this.updatePosition(false, false);
873
- }
874
-
875
- this.unmoveAllSquares();
876
-
877
- move = this.game.move({
878
- from: move.slice(0, 2),
879
- to: move.slice(2, 4),
880
- promotion: move.length === 5 ? move[4] : null
881
- });
882
-
883
-
884
- this.history.push(move);
885
-
886
- this.updatePosition(false, animation);
887
-
888
- this.moved(move['to']);
889
- this.moved(move['from']);
890
-
891
- this.dehintAllSquares();
892
-
893
- this.config.onMoveEnd(move['from'] + move['to'] + (move['promotion'] ? move['promotion'] : ''));
894
-
895
- return true;
896
-
897
-
898
- }
899
-
900
- moved(square) {
901
- this.checkSquare(square);
902
- if (!this.config.moveHighlight) return;
903
- let elem = this.celle[square];
904
- if (elem.className.includes(' movedSquareWhite') || elem.className.includes(' movedSquareBlack')) return;
905
- if (this.isWhiteSquare(square)) elem.className += ' movedSquareWhite';
906
- else elem.className += ' movedSquareBlack';
907
- }
908
-
909
- unmoved(square) {
910
- this.checkSquare(square);
911
- if (!this.config.moveHighlight) return;
912
- let elem = this.celle[square];
913
- if (this.isWhiteSquare(square)) elem.className = elem.className.replace(' movedSquareWhite', '');
914
- else elem.className = elem.className.replace(' movedSquareBlack', '');
915
- }
916
-
917
- unmoveAllSquares() {
918
- for (let casella in this.celle) {
919
- this.unmoved(casella);
920
- }
921
- return;
922
- }
923
-
924
- legalMove(mossa) {
925
- let legalMoves = this.legalMoves(mossa.slice(0, 2));
926
- for (let i in legalMoves) {
927
- if (legalMoves[i]['to'] === mossa.slice(2, 4) && (mossa.length === 4 || mossa[4] === legalMoves[i]['promotion'])) return true;
928
- }
929
-
930
- return false;
931
- }
932
-
933
- legalMoves(from = null, verb = true) {
934
- if (from) this.checkSquare(from);
935
- else return this.game.moves({ verbose: verb });
936
- return this.game.moves({ square: from, verbose: verb });
937
- }
938
-
939
- lastMove() {
940
- return this.history[this.history.length - 1];
941
- }
942
-
943
- getHistory() {
944
- return this.history;
945
- }
946
-
947
- // State
948
-
949
- isGameOver() {
950
- if (this.game.game_over()) {
951
- if (this.game.in_checkmate()) return this.game.turn() === 'w' ? 'b' : 'w';
952
- return 'd';
953
- }
954
- return null;
955
- }
956
-
957
- turn() {
958
- return this.game.turn();
959
- }
960
-
961
- getOrientation() {
962
- return this.config.orientation;
963
- }
964
-
965
- orientation(color) {
966
- if ((color === 'w' || color === 'b') && color !== this.config.orientation) this.flip();
967
- }
968
-
969
- // Position
970
-
971
- chageFenTurn(fen, color) {
972
- let parts = fen.split(' ');
973
- parts[1] = color;
974
- return parts.join(' ');
975
- }
976
-
977
- position(position, color = null) {
978
- this.initParams();
979
- this.dehintAllSquares();
980
- this.deselectAllSquares();
981
- this.unmoveAllSquares();
982
- this.buildGame(position);
983
- position = this.game.fen();
984
- if (!color) color = position.split(' ')[1];
985
- let change_color = this.config.orientation !== color;
986
- this.config.setOrientation(color);
987
- this.game = new Chess(position);
988
- this.updatePosition(change_color);
989
- }
990
-
991
- flip() {
992
- let position = this.game.fen();
993
- this.position(position, this.config.orientation === 'w' ? 'b' : 'w');
994
- }
995
-
996
- playerTurn() { // Restituisce true se è il turno del giocatore
997
- return this.config.orientation === this.game.turn();
998
- }
999
-
1000
- isWhiteSquare(square) {
1001
- this.checkSquare(square);
1002
- let letters = 'abcdefgh';
1003
- return (letters.indexOf(square[0]) + parseInt(square[1])) % 2 === 0;
1004
- }
1005
-
1006
- isWhiteOriented() {
1007
- return this.config.orientation === 'w';
1008
- }
1009
-
1010
- updatePosition(change_color = false, animation = this.config.moveAnimation) {
1011
- if (change_color) {
1012
- this.renameSquares();
1013
- }
1014
- this.updatePieces(animation);
1015
- }
1016
-
1017
- renameSquares() {
1018
- let new_celle = {};
1019
- let new_pezzi = {};
1020
- let new_pieces = {};
1021
- for (let elem in this.celle) {
1022
- let square = this.celle[elem];
1023
- let id = square.id;
1024
- let [row, col] = this.getSquareCoord(id);
1025
- let new_row = 7 - row;
1026
- let new_col = 7 - col;
1027
- square.id = this.getSquareID(new_row, new_col);
1028
- new_celle[square.id] = square;
1029
- if (this.pezzi[id]) {
1030
- new_pezzi[square.id] = this.pezzi[id];
1031
- new_pieces[(this.pezzi[id]['piece'], square.id)] = this.pieces[(this.pezzi[id]['piece'], id)];
1032
- }
1033
-
1034
- }
1035
- this.celle = new_celle;
1036
- this.pezzi = new_pezzi;
1037
- this.pieces = new_pieces;
1038
- }
1039
-
1040
- getPosition(mode) {
1041
- if (!mode || mode === 'fen') return this.game.fen();
1042
- let dict = {};
1043
- for (let square in this.celle) {
1044
- let piece = this.piece(square);
1045
- if (piece) dict[square] = piece;
1046
- }
1047
- return dict;
1048
- }
1049
-
1050
- // Squares
1051
-
1052
- checkSquare(square) {
1053
- if (!square) return;
1054
- if (['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'].indexOf(square[0]) === -1 || ['1', '2', '3', '4', '5', '6', '7', '8'].indexOf(square[1]) === -1) throw new Error('Invalid square - ' + square + ' - must be a valid square like "a1" or "h8"');
1055
- }
1056
-
1057
- getSquareCoord(coord) {
1058
- let letters = 'abcdefgh';
1059
- if (this.isWhiteOriented()) {
1060
- return [8 - parseInt(coord[1]), letters.indexOf(coord[0])];
1061
- }
1062
- return [parseInt(coord[1]) - 1, 7 - letters.indexOf(coord[0])];
1063
- }
1064
-
1065
- resetSquare(square) {
1066
- let elem = this.celle[square];
1067
- elem.className = 'square ' + (this.isWhiteSquare(square) ? 'whiteSquare' : 'blackSquare');
1068
- }
1069
-
1070
- getSquareID(row, col) {
1071
- row = parseInt(row);
1072
- col = parseInt(col);
1073
- if (this.isWhiteOriented()) {
1074
- row = 8 - row;
1075
- col = col + 1;
1076
- } else {
1077
- row = row + 1;
1078
- col = 8 - col;
1079
- }
1080
- let letters = 'abcdefgh';
1081
- let letter = letters[col - 1];
1082
- return letter + row;
1083
- }
1084
-
1085
- removeSquares() { // Rimuove le caselle dalla Chessboard
1086
- for (let casella in this.celle) {
1087
- this.board.removeChild(this.celle[casella]);
1088
- }
1089
- this.celle = {};
1090
- }
1091
-
1092
- clear(animation = true) {
1093
- this.game.clear();
1094
- this.updatePosition(null, animation);
1095
- }
1096
-
1097
- // Highlight
1098
-
1099
- highlight(square) {
1100
- if (!square || !this.celle[square] || !this.config.overHighlight) return;
1101
- let elem = this.celle[square];
1102
- if (elem.className.includes('highlighted')) return;
1103
- elem.className += ' highlighted';
1104
- }
1105
-
1106
- dehighlight(square) {
1107
- if (!square || !this.celle[square] || !this.config.overHighlight) return;
1108
- this.checkSquare(square);
1109
- let elem = this.celle[square];
1110
- elem.className = elem.className.replace(' highlighted', '');
1111
- }
1112
-
1113
-
1114
- // Promotion
1115
-
1116
- coverSquare(square) {
1117
- let cover = document.createElement("div");
1118
- cover.className = "square cover";
1119
- this.celle[square].appendChild(cover);
1120
- }
1121
-
1122
- removeCover(square) {
1123
- let elem = this.celle[square];
1124
- let figli = elem.childNodes;
1125
-
1126
- for (let i = figli.length - 1; i >= 0; i--) {
1127
- if (figli[i].className.includes('cover')) {
1128
- elem.removeChild(figli[i]);
1129
- }
1130
- }
1131
- }
1132
-
1133
- removeAllCovers() {
1134
- for (let casella in this.celle) {
1135
- this.removeCover(casella);
1136
- }
1137
- }
1138
-
1139
- promoteSquare(square, piece) {
1140
- let choice = document.createElement("div");
1141
- choice.className = "square choice";
1142
-
1143
- let img = document.createElement("img");
1144
- img.className = "piece choicable";
1145
- img.src = this.getPiecePath(piece);
1146
- choice.appendChild(img);
1147
-
1148
- this.celle[square].appendChild(choice);
1149
-
1150
- return choice;
1151
- }
1152
-
1153
- depromoteSquare(square) {
1154
- let elem = this.celle[square];
1155
- let figli = elem.childNodes;
1156
-
1157
- for (let i = figli.length - 1; i >= 0; i--) {
1158
- if (figli[i].className.includes('choice')) {
1159
- elem.removeChild(figli[i]);
1160
- }
1161
- }
1162
- }
1163
-
1164
- depromoteAllSquares() {
1165
- for (let casella in this.celle) {
1166
- this.depromoteSquare(casella);
1167
- }
1168
- }
1169
-
1170
- promote(mossa) {
1171
-
1172
- if (!this.config.onlyLegalMoves) return false;
1173
-
1174
- let to = mossa.slice(2, 4);
1175
- let from = mossa.slice(0, 2);
1176
- let pezzo = this.game.get(from);
1177
- let [row, col] = this.getSquareCoord(to);
1178
- let choices = ['q', 'r', 'b', 'n']
1179
-
1180
- if (pezzo['type'] !== 'p' || !(row === 0 || row === 7)) return false;
1181
-
1182
- this.promoting = true;
1183
-
1184
- for (let casella in this.celle) {
1185
- let [rowCurr, colCurr] = this.getSquareCoord(casella);
1186
-
1187
- if (col === colCurr && Math.abs(row - rowCurr) <= 3) {
1188
-
1189
- let choice = this.promoteSquare(casella, choices[Math.abs(row - rowCurr)] + pezzo['color']);
1190
- choice.addEventListener('click', () => {
1191
- this.onClick(to + choices[Math.abs(row - rowCurr)]);
1192
- });
1193
-
1194
- } else {
1195
- this.coverSquare(casella);
1196
- }
1197
- }
1198
-
1199
- this.lastSquare = from;
1200
-
1201
- return true;
1202
- }
1203
-
1204
- // Other
1205
-
1206
- transitionTimingFunction(x, type = 'ease') {
1207
- switch (type) {
1208
- case 'linear':
1209
- return x;
1210
- case 'ease':
1211
- return (x ** 2) * (3 - 2 * x);
1212
- case 'ease-in':
1213
- return x ** 2;
1214
- case 'ease-out':
1215
- return -1 * (x - 1) ** 2 + 1;
1216
- case 'ease-in-out':
1217
- return (x < 0.5) ? 2 * x ** 2 : 4 * x - 2 * x ** 2 - 1;
1218
- }
1219
- }
1220
- }