From: Benjamin Auder Date: Mon, 20 Apr 2020 22:57:50 +0000 (+0200) Subject: Some fixes, draw lines on board, add 7 variants X-Git-Url: https://git.auder.net/variants/Chakart/css/assets/doc/html/R.css?a=commitdiff_plain;h=107dc1bd5361e2538b1551bdcc37c1e90a444b83;p=vchess.git Some fixes, draw lines on board, add 7 variants --- diff --git a/TODO b/TODO index c1197fa8..2fc316ba 100644 --- a/TODO +++ b/TODO @@ -1,45 +1,31 @@ Issue: embedded rules language not updated when language is set (in Analyse, Game and Problems) -Chakart :) -https://www.chessvariants.com/d.betza/chessvar/trapdoor.html https://www.chessvariants.com/crossover.dir/koopachess.html --> Can a stunned piece capture? Maybe not. ...recover? After 5 moves? Never? - -Bicolour Chess (Gabriel Authier, 1958). v1 et v2 : (Roméo Bédoni, 1958) -Kings are subject to check and checkmate by -own as well as opponent’s pieces. The Q and -QN are interchanged in the array -. -v2: y but a player may capture his -own men (TODO: only v2?) - -Berolina Grid Chess, also known as -Gridolina (originator not noted). A -combination of Berolina and Grid Chess. -Better than Grid Chess since Berolina pawns -cross grid lines more easily. Described in -World Game Review 10 as the most popular of -the NOST combination games. (Nost-algia -150, also Nost-algia 112 ‘not seen’) ---> pourquoi pas, mais faudra pouvoir tracer des lignes sur plateau (Ball, Koth, Sittuyin, celle-là, Rococo) ++ Chakart :) https://www.chessvariants.com/diffmove.dir/checkers.html --> move forward (Multhopp) in 1974 by Hans Multhopp -https://www.chessvariants.com/diffmove.dir/checkers.html +https://www.chessvariants.com/diffmove.dir/checkers.html --> "Forward" +Clorange: Clockwork Orange Chess (Fergus Duniho, 1999). https://www.chessvariants.com/other.dir/clockworkorange.html implem : pieces code, yellow/red, easy -http://abrobecker.free.fr/chess/fairyblitz.htm#football -Le gagnant est le premier joueur à marquer un but, càd celui qui arrive à installer une de ses pièces dans les cages adverses: d8,e8 pour les blancs et d1,e1 pour les noirs. +https://www.chessvariants.com/difftaking.dir/replacement.html + +https://www.chessvariants.com/other.dir/pocket.html +https://www.chessvariants.com/other.dir/fugue.html +https://www.chessvariants.com/rules/spartan-chess +https://www.chessvariants.com/mvopponent.dir/avalanche.html + +https://www.chessvariants.com/mvopponent.dir/hypnotic-chess.html +https://www.chessvariants.com/mvopponent.dir/mesmer-chess.html -Recycle1 et Recycle2 (--> celle-là) -http://abrobecker.free.fr/chess/fairyblitz.htm#deplaceurdevivants -Philippe Rouzaud, Phénix 151-152, mai 2006): Un camp peut, à la place d'un coup orthodoxe, capturer une de ses pièces et replacer la pièce capturée immédiatement sur l'échiquier. Un roi peut rester en échec durant cette action. Une pièce déplacée sur l'échiquier peut mater. Un pion ne peut pas être déplacé en première ou dernière rangée. Un roi peut déplacer et être déplacé, y compris pour se soustraire à un échec. Le roque ne peut se faire que de manière orthodoxe. -Rouzaud-Banaddou: 1.Fxb2 (=f5) Dxc7 (=e6) 2.fxe6 dxe6 3.Txb1 (=b5) Dxe7 (=c7) 4.Txb2 (=a3) Dxf7 (=d6) 5.Txg1 (=g5) Dxg7 (=f6) 6.Txf1 (=f7)+ Rxf8 (=h4) 7.Fxb2 (=e8) Rxg7 (=c5) 8.Rxd1 (=f8)+ Rxh8 (=g7) 9.Dxg8+ Txg8 10.Txg8# ---> Implémenté comme Dynamo, déplacement d'une pièce éventuellement avec self-capture, puis capture (sur case vide), forcée si premier coup illégal. +===== -http://abrobecker.free.fr/chess/fairyblitz.htm#madrasi -Madrasi Chess, Abdul J. Karwathar, 1979): Deux pièces de même nature (excepté les rois) qui s'observent, se paralysent mutuellement en perdant tout pouvoir (déplacement, prise, donner échec ou mat) sauf celui de paralyser une autre pièce. -1.e4 e5 2.Cf3 Cc6 3.Fc4 Fc5 4.Cxe5 d6 5.d4 (5.Fxf7+ Rxf7 est légal; ou 5.Dh5 Fe6 immobilisant le Fc4) 5...Fxd4 6.Dxd4 dxe5 et la Dame blanche est perdue. +weiqi, go13, go9, gomoku, reversi +avalam, qoridor, xiangqi, draughts, draughts8 +(puis quand hexaboards peut-être: hexavariants + Hex) +Byo-yomi possible: 1h+b15,5m (15 pierres 5 minutes) diff --git a/client/public/images/pieces/Absorption/ba.svg b/client/public/images/pieces/Absorption/ba.svg new file mode 100644 index 00000000..0215b879 --- /dev/null +++ b/client/public/images/pieces/Absorption/ba.svg @@ -0,0 +1,232 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + diff --git a/client/public/images/pieces/Absorption/be.svg b/client/public/images/pieces/Absorption/be.svg new file mode 100644 index 00000000..fd548016 --- /dev/null +++ b/client/public/images/pieces/Absorption/be.svg @@ -0,0 +1,205 @@ + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/client/public/images/pieces/Absorption/bs.svg b/client/public/images/pieces/Absorption/bs.svg new file mode 100644 index 00000000..afc27f05 --- /dev/null +++ b/client/public/images/pieces/Absorption/bs.svg @@ -0,0 +1,156 @@ + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + diff --git a/client/public/images/pieces/Absorption/wa.svg b/client/public/images/pieces/Absorption/wa.svg new file mode 100644 index 00000000..beeaaea1 --- /dev/null +++ b/client/public/images/pieces/Absorption/wa.svg @@ -0,0 +1,25 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + diff --git a/client/public/images/pieces/Absorption/we.svg b/client/public/images/pieces/Absorption/we.svg new file mode 100644 index 00000000..fd0288db --- /dev/null +++ b/client/public/images/pieces/Absorption/we.svg @@ -0,0 +1,175 @@ + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/client/public/images/pieces/Absorption/ws.svg b/client/public/images/pieces/Absorption/ws.svg new file mode 100644 index 00000000..b45ea509 --- /dev/null +++ b/client/public/images/pieces/Absorption/ws.svg @@ -0,0 +1,152 @@ + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + diff --git a/client/src/base_rules.js b/client/src/base_rules.js index 53001f63..99de6265 100644 --- a/client/src/base_rules.js +++ b/client/src/base_rules.js @@ -93,6 +93,25 @@ export const ChessRules = class ChessRules { return V.CanFlip; } + // For (generally old) variants without checkered board + static get Monochrome() { + return false; + } + + // Some variants require lines drawing + static get Lines() { + if (V.Monochrome) { + let lines = []; + // Draw all inter-squares lines + for (let i = 0; i <= V.size.x; i++) + lines.push([[i, 0], [i, V.size.y]]); + for (let j = 0; j <= V.size.y; j++) + lines.push([[0, j], [V.size.x, j]]); + return lines; + } + return null; + } + // Some variants use click infos: doClick() { return null; @@ -998,9 +1017,8 @@ export const ChessRules = class ChessRules { if (this.board[i][j] != V.EMPTY && this.getColor(i, j) == color) { const moves = this.getPotentialMovesFrom([i, j]); if (moves.length > 0) { - for (let k = 0; k < moves.length; k++) { + for (let k = 0; k < moves.length; k++) if (this.filterValid([moves[k]]).length > 0) return true; - } } } } @@ -1042,21 +1060,15 @@ export const ChessRules = class ChessRules { } // Is square x,y attacked by 'color' pawns ? - isAttackedByPawn([x, y], color) { + isAttackedByPawn(sq, color) { const pawnShift = (color == "w" ? 1 : -1); - if (x + pawnShift >= 0 && x + pawnShift < V.size.x) { - for (let i of [-1, 1]) { - if ( - y + i >= 0 && - y + i < V.size.y && - this.getPiece(x + pawnShift, y + i) == V.PAWN && - this.getColor(x + pawnShift, y + i) == color - ) { - return true; - } - } - } - return false; + return this.isAttackedBySlideNJump( + sq, + color, + V.PAWN, + [[pawnShift, 1], [pawnShift, -1]], + "oneStep" + ); } // Is square x,y attacked by 'color' rooks ? diff --git a/client/src/components/BaseGame.vue b/client/src/components/BaseGame.vue index e309c5df..70a304b8 100644 --- a/client/src/components/BaseGame.vue +++ b/client/src/components/BaseGame.vue @@ -55,7 +55,7 @@ div#baseGame @showrules="showRules" @analyze="toggleAnalyze" @goto-move="gotoMove" - @reset-arrows="resetArrows" + @redraw-board="redrawBoard" ) .clearer @@ -200,9 +200,8 @@ export default { if (e.deltaY < 0) this.undo(); else if (e.deltaY > 0) this.play(); }, - resetArrows: function() { - // TODO: make arrows scale with board, and remove this - this.$refs["board"].cancelResetArrows(); + redrawBoard: function() { + this.$refs["board"].re_setDrawings(); }, showRules: function() { // The button is here only on Game page: diff --git a/client/src/components/Board.vue b/client/src/components/Board.vue index 8a42d34e..29c00645 100644 --- a/client/src/components/Board.vue +++ b/client/src/components/Board.vue @@ -22,10 +22,11 @@ export default { mobileBrowser: ("ontouchstart" in window), possibleMoves: [], //filled after each valid click/dragstart choices: [], //promotion pieces, or checkered captures... (as moves) + containerPos: null, selectedPiece: null, //moving piece (or clicked piece) start: null, //pixels coordinates + id of starting square (click or drag) startArrow: null, - movingArrow: { x: -1, y: -1 }, + movingArrow: null, arrows: [], //object of {start: x,y / end: x,y} circles: {}, //object of squares' ID --> true (TODO: use a set?) click: "", @@ -36,11 +37,10 @@ export default { render(h) { if (!this.vr) { // Return empty div of class 'game' to avoid error when setting size - return h("div", { - class: { - game: true - } - }); + return h( + "div", + { "class": { game: true } } + ); } const [sizeX, sizeY] = [V.size.x, V.size.y]; // Precompute hints squares to facilitate rendering @@ -100,6 +100,7 @@ export default { const gameDiv = h( "div", { + attrs: { id: "gamePosition" }, "class": { game: true, clearer: true @@ -173,8 +174,8 @@ export default { "class": { board: true, ["board" + sizeY]: true, - "light-square": lightSquare, - "dark-square": !lightSquare, + "light-square": lightSquare && !V.Monochrome, + "dark-square": !lightSquare || !!V.Monochrome, [this.settings.bcolor]: true, "in-shadow": inShadow(ci, cj), "highlight-light": inHighlight(ci, cj) && lightSquare, @@ -197,6 +198,8 @@ export default { if (!!this.vr.reserve) { const playingColor = this.userColor || "w"; //default for an observer const shiftIdx = playingColor == "w" ? 0 : 1; + // Some variants have more than sizeY reserve pieces (Clorange: 10) + const reserveSquareNb = Math.max(sizeY, V.RESERVE_PIECES.length); let myReservePiecesArray = []; for (let i = 0; i < V.RESERVE_PIECES.length; i++) { const qty = this.vr.reserve[playingColor][V.RESERVE_PIECES[i]]; @@ -204,7 +207,7 @@ export default { h( "div", { - "class": { board: true, ["board" + sizeY]: true }, + "class": { board: true, ["board" + reserveSquareNb]: true }, attrs: { id: getSquareId({ x: sizeX + shiftIdx, y: i }) }, style: { opacity: qty > 0 ? 1 : 0.35 } }, @@ -231,7 +234,7 @@ export default { h( "div", { - "class": { board: true, ["board" + sizeY]: true }, + "class": { board: true, ["board" + reserveSquareNb]: true }, attrs: { id: getSquareId({ x: sizeX + (1 - shiftIdx), y: i }) }, style: { opacity: qty > 0 ? 1 : 0.35 } }, @@ -256,7 +259,8 @@ export default { ); // Center reserves, assuming same number of pieces for each side: const nbReservePieces = myReservePiecesArray.length; - const marginLeft = ((100 - nbReservePieces * (100 / sizeY)) / 2) + "%"; + const marginLeft = + ((100 - nbReservePieces * (100 / reserveSquareNb)) / 2) + "%"; const reserveTop = h( "div", @@ -311,12 +315,10 @@ export default { } elementArray.push(gameDiv); if (!!this.vr.reserve) elementArray.push(reserveBottom); - const boardElt = document.querySelector(".game"); - // boardElt might be undefine (at first drawing), - // but it won't be used in this case. - const squareWidth = (!!boardElt ? boardElt.offsetWidth / sizeY : 42); + const boardElt = document.getElementById("gamePosition"); + // boardElt might be undefine (at first drawing) if (this.choices.length > 0 && !!boardElt) { - // No choices to show at first drawing + const squareWidth = boardElt.offsetWidth / sizeY; const offset = [boardElt.offsetTop, boardElt.offsetLeft]; const maxNbeltsPerRow = Math.min(this.choices.length, sizeY); let topOffset = offset[0] + (sizeY / 2) * squareWidth - squareWidth / 2; @@ -391,98 +393,6 @@ export default { ); elementArray.unshift(choices); } - if ( - !this.mobileBrowser && - (this.arrows.length > 0 || this.movingArrow.x >= 0) - ) { - let svgArrows = []; - const arrowWidth = squareWidth / 4; - this.arrows.forEach(a => { - const endPoint = this.adjustEndArrow(a.start, a.end, squareWidth); - svgArrows.push( - h( - "path", - { - "class": { "svg-arrow": true }, - attrs: { - d: ( - "M" + a.start.x + "," + a.start.y + " " + - "L" + endPoint.x + "," + endPoint.y - ), - style: "stroke-width:" + arrowWidth + "px" - } - } - ) - ); - }); - if (this.movingArrow.x >= 0) { - const endPoint = - this.adjustEndArrow(this.startArrow, this.movingArrow, squareWidth); - svgArrows.push( - h( - "path", - { - "class": { "svg-arrow": true }, - attrs: { - d: ( - "M" + this.startArrow.x + "," + this.startArrow.y + " " + - "L" + endPoint.x + "," + endPoint.y - ), - style: "stroke-width:" + arrowWidth + "px" - } - } - ) - ); - } - // Add SVG element for drawing arrows - elementArray.push( - h( - "svg", - { - attrs: { - id: "arrowCanvas", - stroke: "none" - } - }, - [ - h( - "defs", - {}, - [ - h( - "marker", - { - attrs: { - id: "arrow", - markerWidth: (2 * arrowWidth) + "px", - markerHeight: (3 * arrowWidth) + "px", - markerUnits: "userSpaceOnUse", - refX: "0", - refY: (1.5 * arrowWidth) + "px", - orient: "auto" - } - }, - [ - h( - "path", - { - "class": { "arrow-head": true }, - attrs: { - d: ( - "M0,0 L0," + (3 * arrowWidth) + " L" + - (2 * arrowWidth) + "," + (1.5 * arrowWidth) + " z" - ) - } - } - ) - ] - ) - ] - ) - ].concat(svgArrows) - ) - ); - } let onEvents = {}; // NOTE: click = mousedown + mouseup if (this.mobileBrowser) { @@ -503,7 +413,16 @@ export default { } }; } - return h("div", onEvents, elementArray); + return ( + h( + "div", + Object.assign({ attrs: { id: "rootBoardElement" } }, onEvents), + elementArray + ) + ); + }, + updated: function() { + this.re_setDrawings(); }, methods: { blockContextMenu: function(e) { @@ -515,23 +434,166 @@ export default { this.startArrow = null; this.arrows = []; this.circles = {}; + const curCanvas = document.getElementById("arrowCanvas"); + if (!!curCanvas) curCanvas.parentNode.removeChild(curCanvas); + }, + coordsToXY: function(coords, top, left, squareWidth) { + return { + // [1] for x and [0] for y because conventions in rules are inversed. + x: ( + left + window.scrollX + + ( + squareWidth * + (this.orientation == 'w' ? coords[1] : (V.size.y - coords[1])) + ) + ), + y: ( + top + window.scrollY + + ( + squareWidth * + (this.orientation == 'w' ? coords[0] : (V.size.x - coords[0])) + ) + ) + }; }, - adjustEndArrow: function(start, end, squareWidth) { + computeEndArrow: function(start, end, top, left, squareWidth) { + const endCoords = this.coordsToXY(end, top, left, squareWidth); + const delta = [endCoords.x - start.x, endCoords.y - start.y]; + const dist = Math.sqrt(delta[0] * delta[0] + delta[1] * delta[1]); // Simple heuristic for now, just remove 1/3 square. // TODO: should depend on the orientation. - const delta = [end.x - start.x, end.y - start.y]; - const dist = Math.sqrt(delta[0] * delta[0] + delta[1] * delta[1]); const fracSqWidth = squareWidth / 3; return { - x: end.x - delta[0] * fracSqWidth / dist, - y: end.y - delta[1] * fracSqWidth / dist + x: endCoords.x - delta[0] * fracSqWidth / dist, + y: endCoords.y - delta[1] * fracSqWidth / dist }; }, + drawCurrentArrow: function() { + const boardElt = document.getElementById("gamePosition"); + const squareWidth = boardElt.offsetWidth / V.size.y; + const bPos = boardElt.getBoundingClientRect(); + const aStart = + this.coordsToXY( + [this.startArrow[0] + 0.5, this.startArrow[1] + 0.5], + bPos.top, bPos.left, squareWidth); + const aEnd = + this.computeEndArrow( + aStart, [this.movingArrow[0] + 0.5, this.movingArrow[1] + 0.5], + bPos.top, bPos.left, squareWidth); + let currentArrow = document.getElementById("currentArrow"); + const d = + "M" + aStart.x + "," + aStart.y + " " + "L" + aEnd.x + "," + aEnd.y; + const arrowWidth = squareWidth / 4; + if (!!currentArrow) currentArrow.setAttribute("d", d); + else { + let domArrow = + document.createElementNS("http://www.w3.org/2000/svg", "path"); + domArrow.classList.add("svg-arrow"); + domArrow.id = "currentArrow"; + domArrow.setAttribute("d", d); + domArrow.style = "stroke-width:" + arrowWidth + "px"; + document.getElementById("arrowCanvas") + .insertAdjacentElement("beforeend", domArrow); + } + }, + addArrow: function(arrow) { + this.arrows.push(arrow); + // Also add to DOM: + const boardElt = document.getElementById("gamePosition"); + const squareWidth = boardElt.offsetWidth / V.size.y; + const bPos = boardElt.getBoundingClientRect(); + const newArrow = + this.getSvgArrow(arrow, bPos.top, bPos.left, squareWidth); + document.getElementById("arrowCanvas") + .insertAdjacentElement("beforeend", newArrow); + }, + getSvgArrow: function(arrow, top, left, squareWidth) { + const aStart = + this.coordsToXY( + [arrow.start[0] + 0.5, arrow.start[1] + 0.5], + top, left, squareWidth); + const aEnd = + this.computeEndArrow( + aStart, [arrow.end[0] + 0.5, arrow.end[1] + 0.5], + top, left, squareWidth); + const arrowWidth = squareWidth / 4; + let path = + document.createElementNS("http://www.w3.org/2000/svg", "path"); + path.classList.add("svg-arrow"); + path.setAttribute( + "d", + "M" + aStart.x + "," + aStart.y + " " + "L" + aEnd.x + "," + aEnd.y + ); + path.style = "stroke-width:" + arrowWidth + "px"; + return path; + }, + re_setDrawings: function() { + // Remove current canvas, if any + const curCanvas = document.getElementById("arrowCanvas"); + if (!!curCanvas) curCanvas.parentNode.removeChild(curCanvas); + // Add some drawing on board (for some variants + arrows and circles) + const boardElt = document.getElementById("gamePosition"); + const squareWidth = boardElt.offsetWidth / V.size.y; + const bPos = boardElt.getBoundingClientRect(); + let svgArrows = []; + this.arrows.forEach(a => { + svgArrows.push(this.getSvgArrow(a, bPos.top, bPos.left, squareWidth)); + }); + let vLines = []; + if (!!V.Lines) { + V.Lines.forEach(line => { + const lStart = + this.coordsToXY(line[0], bPos.top, bPos.left, squareWidth); + const lEnd = + this.coordsToXY(line[1], bPos.top, bPos.left, squareWidth); + let path = + document.createElementNS("http://www.w3.org/2000/svg", "path"); + path.classList.add("svg-line"); + path.setAttribute( + "d", + "M" + lStart.x + "," + lStart.y + " " + + "L" + lEnd.x + "," + lEnd.y + ); + vLines.push(path); + }); + } + let arrowCanvas = + document.createElementNS("http://www.w3.org/2000/svg", "svg"); + arrowCanvas.id = "arrowCanvas"; + arrowCanvas.setAttribute("stroke", "none"); + let defs = + document.createElementNS("http://www.w3.org/2000/svg", "defs"); + const arrowWidth = squareWidth / 4; + let marker = + document.createElementNS("http://www.w3.org/2000/svg", "marker"); + marker.id = "arrow"; + marker.setAttribute("markerWidth", (2 * arrowWidth) + "px"); + marker.setAttribute("markerHeight", (3 * arrowWidth) + "px"); + marker.setAttribute("markerUnits", "userSpaceOnUse"); + marker.setAttribute("refX", "0"); + marker.setAttribute("refY", (1.5 * arrowWidth) + "px"); + marker.setAttribute("orient", "auto"); + let head = + document.createElementNS("http://www.w3.org/2000/svg", "path"); + head.classList.add("arrow-head"); + head.setAttribute( + "d", + "M0,0 L0," + (3 * arrowWidth) + " L" + + (2 * arrowWidth) + "," + (1.5 * arrowWidth) + " z" + ); + marker.appendChild(head); + defs.appendChild(marker); + arrowCanvas.appendChild(defs); + svgArrows.concat(vLines).forEach(av => arrowCanvas.appendChild(av)); + document.getElementById("rootBoardElement").appendChild(arrowCanvas); + }, mousedown: function(e) { e.preventDefault(); if (!this.mobileBrowser && e.which != 3) // Cancel current drawing and circles, if any this.cancelResetArrows(); + this.containerPos = + document.getElementById("boardContainer").getBoundingClientRect(); if (this.mobileBrowser || e.which == 1) { // Mouse left button if (!this.start) { @@ -579,24 +641,34 @@ export default { let elem = e.target; // Next loop because of potential marks while (elem.tagName == "IMG") elem = elem.parentNode; - // To center the arrow in square: - const rect = elem.getBoundingClientRect(); - this.startArrow = { - x: rect.x + rect.width / 2, - y: rect.y + rect.width / 2, - id: elem.id - }; + this.startArrow = getSquareFromId(elem.id); } }, mousemove: function(e) { if (!this.selectedPiece && !this.startArrow) return; + // Cancel if off boardContainer + const [offsetX, offsetY] = + this.mobileBrowser + ? + [ + e.changedTouches[0].pageX, + // TODO: fixing attempt for smartphones, removing window.scrollY + e.changedTouches[0].pageY - window.scrollY + ] + : [e.clientX, e.clientY]; + if ( + offsetX < this.containerPos.left || + offsetX > this.containerPos.right || + offsetY < this.containerPos.top || + offsetY > this.containerPos.bottom + ) { + this.selectedPiece = null; + this.startArrow = null; + return; + } e.preventDefault(); if (!!this.selectedPiece) { // There is an active element: move it around - const [offsetX, offsetY] = - this.mobileBrowser - ? [e.changedTouches[0].pageX, e.changedTouches[0].pageY] - : [e.clientX, e.clientY]; Object.assign( this.selectedPiece.style, { @@ -610,12 +682,13 @@ export default { // Next loop because of potential marks while (elem.tagName == "IMG") elem = elem.parentNode; // To center the arrow in square: - if (elem.id != this.startArrow.id) { - const rect = elem.getBoundingClientRect(); - this.movingArrow = { - x: rect.x + rect.width / 2, - y: rect.y + rect.width / 2 - }; + const movingCoords = getSquareFromId(elem.id); + if ( + movingCoords[0] != this.startArrow[0] || + movingCoords[1] != this.startArrow[1] + ) { + this.movingArrow = movingCoords; + this.drawCurrentArrow(); } } }, @@ -630,7 +703,7 @@ export default { this.processMoveAttempt(e); } else if (e.which == 3) { // Mouse right button - this.movingArrow = { x: -1, y: -1 }; + this.movingArrow = null; this.processArrowAttempt(e); } }, @@ -645,7 +718,11 @@ export default { // Obtain the move from start and end squares const [offsetX, offsetY] = this.mobileBrowser - ? [e.changedTouches[0].pageX, e.changedTouches[0].pageY] + ? + [ + e.changedTouches[0].pageX, + e.changedTouches[0].pageY - window.scrollY + ] : [e.clientX, e.clientY]; let landing = document.elementFromPoint(offsetX, offsetY); // Next condition: classList.contains(piece) fails because of marks @@ -676,21 +753,21 @@ export default { let landing = document.elementFromPoint(offsetX, offsetY); // Next condition: classList.contains(piece) fails because of marks while (landing.tagName == "IMG") landing = landing.parentNode; - if (this.startArrow.id == landing.id) + const landingCoords = getSquareFromId(landing.id); + if ( + this.startArrow[0] == landingCoords[0] && + this.startArrow[1] == landingCoords[1] + ) { // Draw (or erase) a circle this.$set(this.circles, landing.id, !this.circles[landing.id]); + } else { // OK: add arrow, landing is a new square - const rect = landing.getBoundingClientRect(); - this.arrows.push({ - start: { - x: this.startArrow.x, - y: this.startArrow.y - }, - end: { - x: rect.x + rect.width / 2, - y: rect.y + rect.width / 2 - } + const currentArrow = document.getElementById("currentArrow"); + currentArrow.parentNode.removeChild(currentArrow); + this.addArrow({ + start: this.startArrow, + end: landingCoords }); } this.startArrow = null; @@ -710,6 +787,29 @@ export default { }; + + diff --git a/server/db/populate.sql b/server/db/populate.sql index 51dae3fe..a3eb2827 100644 --- a/server/db/populate.sql +++ b/server/db/populate.sql @@ -8,6 +8,7 @@ insert or ignore into Variants (name, description, noProblems) values ('Synchrone', 'Play at the same time', true); insert or ignore into Variants (name, description) values + ('Absorption', 'Absorb powers'), ('Alice', 'Both sides of the mirror'), ('Allmate1', 'Mate any piece (v1)'), ('Allmate2', 'Mate any piece (v2)'), @@ -21,6 +22,7 @@ insert or ignore into Variants (name, description) values ('Baroque', 'Exotic captures'), ('Benedict', 'Change colors'), ('Berolina', 'Pawns move diagonally'), + ('Bicolour', 'Harassed kings'), ('Cannibal', 'Capture powers'), ('Capture', 'Mandatory captures'), ('Checkered1', 'Shared pieces (v1)'), @@ -30,6 +32,7 @@ insert or ignore into Variants (name, description) values ('Circular', 'Run forward'), ('Colorbound', 'The colorbound clobberers'), ('Coregal', 'Two royal pieces'), + ('Coronation', 'Long live the Queen'), ('Crazyhouse', 'Captures reborn'), ('Cylinder', 'Neverending rows'), ('Diamond', 'Rotating board'), @@ -40,8 +43,10 @@ insert or ignore into Variants (name, description) values ('Eightpieces', 'Each piece is unique'), ('Enpassant', 'Capture en passant'), ('Extinction', 'Capture all of a kind'), + ('Football', 'Score a goal'), ('Grand', 'Big board'), ('Grasshopper', 'Long jumps over pieces'), + ('Gridolina', 'Jump the borders'), ('Hamilton', 'Walk on a graph'), ('Horde', 'A pawns cloud'), ('Interweave', 'Interweaved colorbound teams'), @@ -50,6 +55,7 @@ insert or ignore into Variants (name, description) values ('Knightrelay2', 'Move like a knight (v2)'), ('Koth', 'King of the Hill'), ('Losers', 'Get strong at self-mate'), + ('Madrasi', 'Paralyzed pieces'), ('Magnetic', 'Laws of attraction'), ('Makruk', 'Thai Chess'), ('Maxima', 'Occupy the enemy palace'), @@ -74,6 +80,7 @@ insert or ignore into Variants (name, description) values ('Suicide', 'Lose all pieces'), ('Suction', 'Attract opposite king'), ('Takenmake', 'Prolongated captures'), + ('Teleport', 'Reposition pieces'), ('Tencubed', 'Four new pieces'), ('Threechecks', 'Give three checks'), ('Twokings', 'Two kings'),