From c7550017d88ff6eb32e2c76a271a7f9edc4a3bf6 Mon Sep 17 00:00:00 2001 From: Benjamin Auder Date: Thu, 26 Mar 2020 12:23:40 +0100 Subject: [PATCH] Add Orda variant. Some advances in Dynamo draft. Display error message when loading an observed game from another tab --- TODO | 23 +- client/download_objects.sh | 10 +- client/public/images/pieces/Dynamo/empty.svg | 1 + client/public/images/pieces/Orda/ba.svg | 137 ++++++++ client/public/images/pieces/Orda/bh.svg | 197 +++++++++++ client/public/images/pieces/Orda/bk.svg | 215 ++++++++++++ client/public/images/pieces/Orda/bl.svg | 124 +++++++ client/public/images/pieces/Orda/bp.svg | 116 +++++++ client/public/images/pieces/Orda/bq.svg | 101 ++++++ client/public/images/pieces/Orda/by.svg | 241 +++++++++++++ client/public/images/pieces/Orda/wh.svg | 202 +++++++++++ client/public/images/variants/Orda/Archer.png | 1 + .../public/images/variants/Orda/Kheshig.png | 1 + client/public/images/variants/Orda/Lancer.png | 1 + client/public/images/variants/Orda/Orda.png | 1 + client/public/images/variants/Orda/Yurt.png | 1 + client/public/images/variants/README | 2 + client/src/base_rules.js | 6 +- client/src/components/Board.vue | 6 +- client/src/translations/en.js | 3 + client/src/translations/es.js | 3 + client/src/translations/fr.js | 3 + client/src/translations/rules/Dynamo/en.pug | 2 + client/src/translations/rules/Dynamo/es.pug | 2 + client/src/translations/rules/Dynamo/fr.pug | 2 + client/src/translations/rules/Orda/en.pug | 263 ++++++++++++++ client/src/translations/rules/Orda/es.pug | 264 ++++++++++++++ client/src/translations/rules/Orda/fr.pug | 266 +++++++++++++++ client/src/variants/Dynamo.js | 94 ++++- client/src/variants/Eightpieces.js | 11 +- client/src/variants/Orda.js | 323 ++++++++++++++++++ client/src/views/Game.vue | 9 +- client/src/views/Rules.vue | 15 + server/db/populate.sql | 2 + server/sockets.js | 3 + 35 files changed, 2635 insertions(+), 16 deletions(-) create mode 100644 client/public/images/pieces/Dynamo/empty.svg create mode 100644 client/public/images/pieces/Orda/ba.svg create mode 100644 client/public/images/pieces/Orda/bh.svg create mode 100644 client/public/images/pieces/Orda/bk.svg create mode 100644 client/public/images/pieces/Orda/bl.svg create mode 100644 client/public/images/pieces/Orda/bp.svg create mode 100644 client/public/images/pieces/Orda/bq.svg create mode 100644 client/public/images/pieces/Orda/by.svg create mode 100644 client/public/images/pieces/Orda/wh.svg create mode 100644 client/public/images/variants/Orda/Archer.png create mode 100644 client/public/images/variants/Orda/Kheshig.png create mode 100644 client/public/images/variants/Orda/Lancer.png create mode 100644 client/public/images/variants/Orda/Orda.png create mode 100644 client/public/images/variants/Orda/Yurt.png create mode 100644 client/public/images/variants/README create mode 100644 client/src/translations/rules/Dynamo/en.pug create mode 100644 client/src/translations/rules/Dynamo/es.pug create mode 100644 client/src/translations/rules/Dynamo/fr.pug create mode 100644 client/src/translations/rules/Orda/en.pug create mode 100644 client/src/translations/rules/Orda/es.pug create mode 100644 client/src/translations/rules/Orda/fr.pug create mode 100644 client/src/variants/Orda.js diff --git a/TODO b/TODO index 8e81cc7a..df4231ac 100644 --- a/TODO +++ b/TODO @@ -1,7 +1,28 @@ +# Enhancements: +Desktop notifications +Do not remove other challenges when one is accepted? + # New variants +Finish first https://www.chessvariants.com/mvopponent.dir/dynamo.html +https://echekk.fr/spip.php?page=article&id_article=599 + +Monster, Horde, Colorbound +https://www.chessvariants.com/d.betza/chessvar/dan/colclob.html +https://lichess.org/analysis/horde#0 +https://greenchess.net/rules.php?v=monster +https://en.wikipedia.org/wiki/Monster_chess +https://en.wikipedia.org/wiki/Grotesque_(chess) (fun) + Maxima, Interweave, Roccoco +https://www.chessvariants.com/other.dir/rococo.html +https://www.chessvariants.com/dpieces.dir/maxima/maxima.html +https://www.chessvariants.com/other.dir/interweave.html Take(a)n(d)make : if capture a piece, take its power for the last of the turn and make a move like it. If a pawn taken: direction of the capturer, can capture enemy. +http://www.strategems.net/sections/fairy_defs.html +Having captured, a unit must immediately, as part of its move, play a non-capturing move, using ONLY the powers of movement of the captured unit from the capture-square. If no such move is available, the capture is illegal. Promotion by capture occurs only when a pawn arrives on the promotion rank as the result of a Take & Make move. Checks are as in normal chess: after the notional capture of the checked King, the checking unit does not move away from the King’s square. + +Chakart :) -Dynamo chess --> dur... +https://en.wikipedia.org/wiki/Fairy_chess_piece diff --git a/client/download_objects.sh b/client/download_objects.sh index a59fe324..3cb25775 100755 --- a/client/download_objects.sh +++ b/client/download_objects.sh @@ -3,11 +3,15 @@ # Restore binary files (temporary fix - should use git-fat instead) for color in "w" "b"; do for piece in "b" "c" "d" "e" "f" "g" "h" "j" "k" "m" "n" "o" "p" "q" "r" "s"; do - rm public/images/pieces/Eightpieces/tmp_png/"$color$piece".png + rm -f public/images/pieces/Eightpieces/tmp_png/"$color$piece".png wget -q -O public/images/pieces/Eightpieces/tmp_png/"$color$piece".png https://vchess.club/images/pieces/Eightpieces/tmp_png/"$color$piece".png done done -rm public/sounds/newgame.flac +for image in "Orda" "Archer" "Lancer" "Kheshig" "Yurt"; do + rm -f /public/images/variants/Orda/"$image".png + wget -q -O public/images/variants/Orda/"$image".png https://vchess.club/images/variants/Orda/"$image".png +done +rm -f public/sounds/newgame.flac wget -q -O public/sounds/newgame.flac https://vchess.club/sounds/newgame.flac -rm public/favicon.ico +rm -f public/favicon.ico wget -q -O public/favicon.ico https://vchess.club/favicon.ico diff --git a/client/public/images/pieces/Dynamo/empty.svg b/client/public/images/pieces/Dynamo/empty.svg new file mode 100644 index 00000000..08ec9068 --- /dev/null +++ b/client/public/images/pieces/Dynamo/empty.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/client/public/images/pieces/Orda/ba.svg b/client/public/images/pieces/Orda/ba.svg new file mode 100644 index 00000000..87fa4d42 --- /dev/null +++ b/client/public/images/pieces/Orda/ba.svg @@ -0,0 +1,137 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/client/public/images/pieces/Orda/bh.svg b/client/public/images/pieces/Orda/bh.svg new file mode 100644 index 00000000..ecf598cb --- /dev/null +++ b/client/public/images/pieces/Orda/bh.svg @@ -0,0 +1,197 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/client/public/images/pieces/Orda/bk.svg b/client/public/images/pieces/Orda/bk.svg new file mode 100644 index 00000000..7ce96e4a --- /dev/null +++ b/client/public/images/pieces/Orda/bk.svg @@ -0,0 +1,215 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/client/public/images/pieces/Orda/bl.svg b/client/public/images/pieces/Orda/bl.svg new file mode 100644 index 00000000..c7622c3a --- /dev/null +++ b/client/public/images/pieces/Orda/bl.svg @@ -0,0 +1,124 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + diff --git a/client/public/images/pieces/Orda/bp.svg b/client/public/images/pieces/Orda/bp.svg new file mode 100644 index 00000000..4041c5a1 --- /dev/null +++ b/client/public/images/pieces/Orda/bp.svg @@ -0,0 +1,116 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + diff --git a/client/public/images/pieces/Orda/bq.svg b/client/public/images/pieces/Orda/bq.svg new file mode 100644 index 00000000..a37c1f0c --- /dev/null +++ b/client/public/images/pieces/Orda/bq.svg @@ -0,0 +1,101 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + diff --git a/client/public/images/pieces/Orda/by.svg b/client/public/images/pieces/Orda/by.svg new file mode 100644 index 00000000..92c27605 --- /dev/null +++ b/client/public/images/pieces/Orda/by.svg @@ -0,0 +1,241 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/client/public/images/pieces/Orda/wh.svg b/client/public/images/pieces/Orda/wh.svg new file mode 100644 index 00000000..22a0409d --- /dev/null +++ b/client/public/images/pieces/Orda/wh.svg @@ -0,0 +1,202 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/client/public/images/variants/Orda/Archer.png b/client/public/images/variants/Orda/Archer.png new file mode 100644 index 00000000..f2d63e92 --- /dev/null +++ b/client/public/images/variants/Orda/Archer.png @@ -0,0 +1 @@ +#$# git-fat 95df899f13b1adefad85a23ce0f0acd17396b4b4 14751 diff --git a/client/public/images/variants/Orda/Kheshig.png b/client/public/images/variants/Orda/Kheshig.png new file mode 100644 index 00000000..1f005fa2 --- /dev/null +++ b/client/public/images/variants/Orda/Kheshig.png @@ -0,0 +1 @@ +#$# git-fat b608821fb2bf1200c83124776a0d027e6cbc3172 8879 diff --git a/client/public/images/variants/Orda/Lancer.png b/client/public/images/variants/Orda/Lancer.png new file mode 100644 index 00000000..f0ae73ef --- /dev/null +++ b/client/public/images/variants/Orda/Lancer.png @@ -0,0 +1 @@ +#$# git-fat 0aae5c4c8931f94b873015655f24cb9e4c9a0b04 13796 diff --git a/client/public/images/variants/Orda/Orda.png b/client/public/images/variants/Orda/Orda.png new file mode 100644 index 00000000..69a74fc4 --- /dev/null +++ b/client/public/images/variants/Orda/Orda.png @@ -0,0 +1 @@ +#$# git-fat 9f7c4f64cccdb2c7556cdff2c79a1ad81530e48c 390147 diff --git a/client/public/images/variants/Orda/Yurt.png b/client/public/images/variants/Orda/Yurt.png new file mode 100644 index 00000000..82b130bc --- /dev/null +++ b/client/public/images/variants/Orda/Yurt.png @@ -0,0 +1 @@ +#$# git-fat cc8411397ba9c18c7615b626c1789ec98083259f 6547 diff --git a/client/public/images/variants/README b/client/public/images/variants/README new file mode 100644 index 00000000..c6a3a75f --- /dev/null +++ b/client/public/images/variants/README @@ -0,0 +1,2 @@ +Here are some binary images used for some variants. +Currently only Orda. diff --git a/client/src/base_rules.js b/client/src/base_rules.js index 37e756e9..177fc9b6 100644 --- a/client/src/base_rules.js +++ b/client/src/base_rules.js @@ -197,8 +197,8 @@ export const ChessRules = class ChessRules { } // Path to promotion pieces (usually the same) - getPPpath(b) { - return this.getPpath(b); + getPPpath(m) { + return this.getPpath(m.appear[0].c + m.appear[0].p); } // Aggregates flags into one object @@ -1094,7 +1094,7 @@ export const ChessRules = class ChessRules { const c = V.GetOppCol(this.turn); const firstRank = (c == "w" ? V.size.x - 1 : 0); // Update castling flags if rooks are moved - const oppCol = V.GetOppCol(c); + const oppCol = this.turn; const oppFirstRank = V.size.x - 1 - firstRank; if (piece == V.KING && move.appear.length > 0) this.castleFlags[c] = [V.size.y, V.size.y]; diff --git a/client/src/components/Board.vue b/client/src/components/Board.vue index d89ee404..0856096a 100644 --- a/client/src/components/Board.vue +++ b/client/src/components/Board.vue @@ -345,10 +345,8 @@ export default { attrs: { src: "/images/pieces/" + - this.vr.getPPpath( - m.appear[0].c + m.appear[0].p, - // Extra arg useful for some variants: - this.orientation) + + // orientation: extra arg useful for some variants: + this.vr.getPPpath(m, this.orientation) + V.IMAGE_EXTENSION }, class: { "choice-piece": true }, diff --git a/client/src/translations/en.js b/client/src/translations/en.js index 7ce045ff..13798874 100644 --- a/client/src/translations/en.js +++ b/client/src/translations/en.js @@ -132,6 +132,7 @@ export const translations = { Subject: "Subject", "Symmetric random": "Symmetric random", "Terminate game?": "Terminate game?", + "The game should be in another tab": "The game should be in another tab", "Three repetitions": "Three repetitions", Time: "Time", "Undetermined result": "Undetermined result", @@ -186,6 +187,7 @@ export const translations = { "Mate any piece (v2)": "Mate any piece (v2)", "Mate the knight": "Mate the knight", "Middle battle": "Middle battle", + "Mongolian Horde": "Mongolian Horde", "Move like a knight (v1)": "Move like a knight (v1)", "Move like a knight (v2)": "Move like a knight (v2)", "Move twice": "Move twice", @@ -194,6 +196,7 @@ export const translations = { "Pawns move diagonally": "Pawns move diagonally", "Play at the same time": "Play at the same time", "Powerful pieces": "Powerful pieces", + "Push and pull": "Push and pull", "Queen disguised as a pawn": "Queen disguised as a pawn", "Reuse pieces": "Reuse pieces", "Reverse captures": "Reverse captures", diff --git a/client/src/translations/es.js b/client/src/translations/es.js index 40ba5c87..72c68dd6 100644 --- a/client/src/translations/es.js +++ b/client/src/translations/es.js @@ -132,6 +132,7 @@ export const translations = { Subject: "Asunto", "Symmetric random": "Aleatorio simétrico", "Terminate game?": "¿Terminar la partida?", + "The game should be in another tab": "la partida debería estar en otra pestaña", "Three repetitions": "Tres repeticiones", Time: "Tiempo", "Undetermined result": "Resultado indeterminado", @@ -186,6 +187,7 @@ export const translations = { "Mate any piece (v2)": "Matar cualquier pieza (v2)", "Mate the knight": "Matar el caballo", "Middle battle": "Batalla media", + "Mongolian Horde": "Horda mongol", "Move like a knight (v1)": "Moverse como un caballo (v1)", "Move like a knight (v2)": "Moverse como un caballo (v2)", "Move twice": "Mover dos veces", @@ -194,6 +196,7 @@ export const translations = { "Pawns move diagonally": "Peones se mueven en diagonal", "Play at the same time": "Jugar al mismo tiempo", "Powerful pieces": "Piezas poderosas", + "Push and pull": "Empujar y tirar", "Queen disguised as a pawn": "Reina disfrazada de peón", "Reuse pieces": "Reutilizar piezas", "Reverse captures": "Capturas invertidas", diff --git a/client/src/translations/fr.js b/client/src/translations/fr.js index 8954f7b1..e0da2f36 100644 --- a/client/src/translations/fr.js +++ b/client/src/translations/fr.js @@ -132,6 +132,7 @@ export const translations = { Subject: "Sujet", "Symmetric random": "Aléatoire symétrique", "Terminate game?": "Stopper la partie ?", + "The game should be in another tab": "La partie devrait être dans un autre onglet", "Three repetitions": "Triple répétition", Time: "Temps", "Undetermined result": "Résultat indéterminé", @@ -186,6 +187,7 @@ export const translations = { "Mate any piece (v2)": "Matez n'importe quelle pièce (v2)", "Mate the knight": "Matez le cavalier", "Middle battle": "Bataille du milieu", + "Mongolian Horde": "Horde mongole", "Move like a knight (v1)": "Bouger comme un cavalier (v1)", "Move like a knight (v2)": "Bouger comme un cavalier (v2)", "Move twice": "Jouer deux coups", @@ -194,6 +196,7 @@ export const translations = { "Pawns move diagonally": "Les pions vont en diagonale", "Play at the same time": "Jouer en même temps", "Powerful pieces": "Pièces puissantes", + "Push and pull": "Pousser et tirer", "Queen disguised as a pawn": "Reine déguisée en pion", "Reuse pieces": "Réutiliser les pièces", "Reverse captures": "Captures inversées", diff --git a/client/src/translations/rules/Dynamo/en.pug b/client/src/translations/rules/Dynamo/en.pug new file mode 100644 index 00000000..2662cdd2 --- /dev/null +++ b/client/src/translations/rules/Dynamo/en.pug @@ -0,0 +1,2 @@ +p.boxed + | TODO: not playable yet! diff --git a/client/src/translations/rules/Dynamo/es.pug b/client/src/translations/rules/Dynamo/es.pug new file mode 100644 index 00000000..6fbe3756 --- /dev/null +++ b/client/src/translations/rules/Dynamo/es.pug @@ -0,0 +1,2 @@ +p.boxed + | TODO: no jugable en este momento! diff --git a/client/src/translations/rules/Dynamo/fr.pug b/client/src/translations/rules/Dynamo/fr.pug new file mode 100644 index 00000000..d16e4b4c --- /dev/null +++ b/client/src/translations/rules/Dynamo/fr.pug @@ -0,0 +1,2 @@ +p.boxed + | TODO: pas jouable pour le moment ! diff --git a/client/src/translations/rules/Orda/en.pug b/client/src/translations/rules/Orda/en.pug new file mode 100644 index 00000000..2ccd5092 --- /dev/null +++ b/client/src/translations/rules/Orda/en.pug @@ -0,0 +1,263 @@ +p.boxed + | The player in second has a different set of pieces, + | moving roughly like "augmented knights". + +img.img-center(src="/images/variants/Orda/Orda.png") + +p + | Orda Chess is a chess variant designed in 2020 by Couch Tomato. + span.italic + | Note: he'd rather remain anonymous :) + | Anyway this text and all the images are from him. + | The idea of the game was to create a true asymmetric chess with + | two different armies. Ralph Betza's + a(href="https://www.chessvariants.com/unequal.dir/cwda.html") + | Chess with Different Armies + | was an inspiration, but the goal was to be a little more streamlined + | with the theme here. + | In this case, the theme of the new army is knight-based movement, + | where most pieces have an element of knight movement. + | Given the knight (or horse) theme, this was modeled after the + | Mongol army and named the Horde. An "orda" was a military structure + | for the people of the Steppes, which also gave rise to the English word + | "horde." The original chess army is named the Kingdom for contrast. + | The game itself is incredibly balanced by engine evaluation (even more + | than standard chess), with a near 50-50 win ratio for + | the Kingdom and Horde. + +h3 General Rules + +ol + li. + Setup is as above. Despite new pieces, the placement of the Horde pieces + mirror their chess counterparts. + li The Kingdom always moves first. + li The Horde cannot castle. + li. + As Horde pawns start on the third rank, they do not have the option to + move two spaces or be captured by en passant. Kingdom pawns retain the + ability to move two spaces initially and to be captured via en passant. + li Pawns can only promote to a queen or kheshig. + li. + An additional method of victory is available: called campmate. Campmate is + achieved by moving one's king into the final rank without being check. + li Other rules, including stalemate and repetition are as in chess. + +h3 Horde Pieces + +p. + There are four new units unique* to the Horde: 2 Lancers, 2 Horse Archers, + 2 Kheshigs, and 1 Yurt (* exception being that the Kingdom can still obtain + a Kheshig by promotion). The Kheshigs are the strongest piece + (knight + king movement) and lead each flank, while the Yurt is a fairly + weak piece unlike the Queen. The Horde's king is called the Khan and looks + different, but is essentially the same as the Kingdom's King, also using + the same abbreviation (K) — the change is purely aesthetic and + thematic. + +p. + The Horde Lancer and Horse Archer are unique in that they capture + differently than movement. Remember that the Horde is horse-based, so the + Lancer and Horse Archer both move like knights. They capture like rooks + and bishops, respectively. The Kheshig is more traditional in that it + captures where it moves; it combines the movements of the knight and king. + Similarly, the Yurt also captures the same way it moves; it moves as the + silver general in Shogi. + +table + tr + th Horde piece + th Kingdom "counterpart" + th Movement + th Capture + tr + td Yurt + td Queen + td "Silver" + td "Silver" + tr + td Horse Archer + td Bishop + td Knight + td Bishop + tr + td Kheshig + td Knight + td Knight+King + td Knight+King + tr + td Lancer + td Rook + td Knight + td Rook + +p. + Details and diagrams of each piece are below. Green dots represent movement, + red dots represent capture, and yellow represents both. + +h4 Yurt (Y) + +img.img-center(src="/images/variants/Orda/Yurt.png") + +p. + The Yurt moves and captures one space diagonally or one space forward. + This is the same as a silver general from Shogi or the bishop/khon + from Makruk. There is only one yurt, starting in the queen's spot, + but unlike the queen, it is very much a minor piece, the weakest piece + in the game aside from a pawn. It should not be underestimated though, + because it is one of the few Horde pieces that can move and capture + the same way. The other two are the Khan and Kheshig, which are the two + most valuable pieces. Therefore the yurt has the unique role of reliably + supporting pawns and other pieces without fear of retaliation. + +p. + A yurt is a mobile home for Mongol and Turkic people in the steppes of + Asia. Their limited mobility but importance for supporting the army is + reflected in this piece. + +h4 Kheshig (H) + +img.img-center(src="/images/variants/Orda/Kheshig.png") + +p. + The Kheshig is a hybrid piece that moves and captures as a knight and + king combined. This piece type is also generically called the centaur. + The kheshig starts in the knight's spot, but unlike the knight, + is the strongest Horde piece. It can be thought of the general that leads + its own troop on each flank. It is generally preferred to keep the kheshigs + safely behind during early to mid game because of their extreme importance + to the Horde in the endgame. + +p. + The kheshigs were the elite imperial guard for the Mongol royalty. + Appropriately, it is incredibly difficult for the Kingdom to checkmate + the khan without at least eliminating one of his kheshigs first. + +h4 Horse Archer (A) + +img.img-center(src="/images/variants/Orda/Archer.png") + +p. + The Horse Archer, or simply abbreviated Archer, is a unique "pseudohybrid" + piece that moves and attacks differently. The archer moves as a knight but + captures as a bishop. Because the archer is not colorbound, + its value is greater than its bishop counterpart. + +p. + Horse Archers were one of the two core components of the Mongol cavalry, + functioning as the light cavalry. Their speed and prowess as mounted + archers made them a unique threat. Their ability to quickly position + themselves for a deadly skewer or fork make them a dangerous threat + for the Kingdom. + +h4 Lancer (L) + +img.img-center(src="/images/variants/Orda/Lancer.png") + +p. + The Lancer is a unique "pseudohybrid" piece that moves and attacks + differently. The lancer moves as a knight but captures as a rook. + Because the lancer is not as mobile as the rook, it is generally + weaker than the rook, and this becomes more pronounced in the endgame, + as it cannot move across the board as quickly as a rook can. + Its value is still comparable to the horse archer. + +p. + Lancers were one of the two core components of the Mongol cavalry, + functioning as the heavy cavalry. Despite being weaker than the rook, + their ability to come into play much earlier in the game is an advantage + that the Horde player should utilize. + +h4 Piece valuation + +p. + Accurate piece values are unknown. However, these are the values used by + Fairy Stockfish, noting that they are generic values, + not necessarily specific to Orda chess. + +table + tr + th Kingdom piece + th Value (Early / Late) + th Horde piece + th Value (Early / Late) + tr + td Pawn + td 120 / 213 + td Pawn + td 120 / 213 + tr + td Queen + td 2538 / 2682 + td Yurt + td 630 / 630 + tr + td Bishop + td 825 / 915 + td Horse Archer + td 1100 / 1200 + tr + td Knight + td 781 / 854 + td Kheshig + td 1600 / 1700 + tr + td Rook + td 1276 / 1380 + td Lancer + td 1050 / 1250 + +p + | For those who want a more simplified approach, this table may be + | an approximation. + span.italic Note: this simplification is used by the weak bot here. + +table + tr + th Kingdom piece + th Value + th Horde piece + th Value + tr + td Pawn + td 1 + td Pawn + td 1 + tr + td Queen + td 9 + td Yurt + td 2 + tr + td Bishop + td 3 + td Horse Archer + td 4 + tr + td Knight + td 3 + td Kheshig + td 7 + tr + td Rook + td 5 + td Lancer + td 4 + +p. + As a whole, the Horde army is weaker than the Kingdom in value + (based on Stockfish valuation). + However, the Horde also starts with pawns in the third rank, + which balances the game. + +h3 Strategy + +p. + The game is still young, so strategy is still being developed! + Much of the data is currently based on Engine play. + The Horde cannot castle. However, a very fundamental component of a + majority Horde openings is to move the Khan to f7. + Reaching this spot in within the first four moves is ideal + — in fact, Fairy Stockfish opened up with Kf7 in 56% of its games. + The rest is variable. + For the Kingdom, d4, g3 and b3 are the most common openings in that order. diff --git a/client/src/translations/rules/Orda/es.pug b/client/src/translations/rules/Orda/es.pug new file mode 100644 index 00000000..a6f2d1bf --- /dev/null +++ b/client/src/translations/rules/Orda/es.pug @@ -0,0 +1,264 @@ +p.boxed + | El segundo jugador tiene un conjunto diferente de piezas, + | moviéndose aproximadamente como "caballos aumentados". + +img.img-center(src="/images/variantes/Orda/Orda.png") + +p + | Orda Chess es una variante inventada en 2020 por Couch Tomato + span.italic + | Nota: él prefiere permanecer en el anonimato :) En cualquier caso, + | la versión Inglés de este texto y todas las imágenes son de él. + | La idea de este juego era conseguir una pelea asimétrica real con + | diferentes ejércitos Las variaciones de Ralph Betza + a(href="https://www.chessvariants.com/unequal.dir/cwda.html") + | con diferentes ejércitos + | fueron una inspiración pero el objetivo era estar en + | adecuación con el tema actual. En nuestro caso, el tema de + | nuevo ejército es como se mueve el caballo: la mayoría de las piezas + | tener un elemento que evoca el movimiento del caballo. + | Dado este "tema del caballo", esta variante fue construida + | después del ejército mongol y llamó a la Horda. Una "orda" era un + | estructura militar para el pueblo de las estepas, y la palabra española + | "horda" viene de ahi. El ejército original se llama "el Reino", para el + | contraste El juego en sí está increíblemente equilibrado según + | evaluación del módulo (en realidad más que para ajedrez estándar), + | con una proporción de ganancias cercana a 50-50 para el Reino y la Horda. + +h3 Reglas generales + +ol + li. + El diseño de las habitaciones se da arriba. Las piezas de la Horda son + partes estándar espejadas, aunque desplazamiento son diferentes + li El Reino siempre hace el primer movimiento. + li La Horda no puede enroquar. + li. + Los peones de la Horda que comienzan en la tercera fila, tampoco pueden + avanzar dos espacios o ser capturado en passant. Peones del Reino + en cuanto a ellos, mantenga estas dos opciones. + li Las únicas promociones posibles son en dama o kheshig. + li. + Es posible una nueva forma de ganar: la "mate de campamento". + Esta "mate" obtenido jugando el rey (sin ser en jaque) en la última fila. + li Las otras reglas se aplican, como el empate o las tablas por repetición. + +h3 Piezas de la Horda + +p. + Hay cuatro nuevas unidades únicas* en la Horda: 2 Lanceros, 2 Arqueros + a caballo, 2 Kheshigs y 1 Yurt (* excepto el kheshig que el + Reino puede obtener por promoción). Los kheshigs son los más + poderoso (desplazamiento de caballo + rey) y lidera cada flanco, mientras + que la yurta es una habitación bastante débil a diferencia de la dama. + El Rey de la Horda se llama Khan y tiene una apariencia diferente, pero es + muévete y captura como el Rey del Reino; se nota por el mismo + abreviatura (K) — el cambio es puramente estético y temática + +p. + Los Lanceros y el Arquero a caballo de la Horda son únicos en el sentido + de que no capturar mientras se mueven. Recuerda que la Horda es + inspirado en una caballería (militar), y por lo tanto los Lanceros y + Arqueros en ambos caballos se mueven como jinetes. Capturan como + la torre y el alfil, respectivamente. El Kheshig es más tradicional porque + captura mientras se mueve; combina los movimientos del rey y el + caballo. La yurta también captura a medida que se mueve: como un + general de plata en el Shogi. + +table + tr + th Pieza de la Horda + th "Contraparte" del Reino + th Desplazamiento + th Captura + tr + td Yurta + td Dama + td "Plata" + td "Plata" + tr + td Arquero + td Alfil + td Caballo + td Alfil + tr + td Kheshig + td Caballo + td Caballo+Rey + td Caballo+Rey + tr + td Lancero + td Torre + td Caballo + td Torre + +p. + Los detalles y diagramas de cada parte se pueden encontrar a continuación. + Los puntos verdes representan los movimientos, el rojo las capturas, + y los amarillos representan ambos. + +h4 Yurta (Y) + +img.img-center(src="/images/variantes/Orda/Yurt.png") + +p. + La yurta se mueve y captura una casilla diagonal o un cuadrado hacia + el frente. Esto corresponde a un general de plata en el Shogi o un + alfil/khon en Makruk. Solo hay una yurta, comenzando en el sitio de la dama, + pero a diferencia de este último corresponde a una pieza (muy) menor: + el más débil en el juego después del peón. Dicho esto, no debería + para ser subestimado, porque es una de las piezas raras de la Horda que + captura a medida que se mueve Los otros dos son el khan y el kheshig: los + dos piezas más preciosas. Entonces la yurta tiene el papel único de + apoyar peones y otras partes sin temor a la rebelión. + +p. + Una yurta es un hábitat móvil para las poblaciones de las estepas + asiáticos. Su movilidad limitada contrasta con su importancia para + apoyar a los militares se refleja en esta pieza. + +h4 Kheshig (H) + +img.img-center(src="/images/variantes/Orda/Kheshig.png") + +p. + El kheshig es una pieza híbrida que se mueve y captura como un rey y un + caballo combinado. Este tipo de pieza también se llama centauro, + genéricamente. El kheshig comienza en la ubicación del jinete, pero a + diferencia de esto la última es la pieza más poderosa de la Horda. + Puedes imaginar como un general que lideraría sus propias tropas en cada + flanco. En general, es preferible mantener a los kheshigs en el refugio + detrás de la apertura hasta la mitad del juego, debido a su extrema + importancia para la Horda en la final. + +p. + Los kheshigs eran la guardia imperial de élite en el reino mongol. + Entonces es apropiado que sea increíblemente difícil para el Reino + matar un khan sin eliminar al menos uno de los kheshigs. + +h4 Arquero a caballo (A) + +img.img-center(src="/images/variantes/Orda/Archer.png") + +p. + El arquero (a caballo) es una pieza única "pseudo-híbrida" que se mueve + y capturar de manera diferente. El arquero tiene los movimientos del + caballo pero captura como alfil. El arquero jugando tanto en casillas + negras como en blancas, es más fuerte que el alfil del Reino. + +p. + Uno de los dos componentes principales de la caballería mongol, + que funciona como una caballería ligera. Su velocidad + y su habilidad los convirtió en una amenaza única. Su capacidad para + posicionarse rápidamente para un hilo o tenedor mortal + los convierte en una amenaza peligrosa para el Reino. + +h4 Lancero (L) + +img.img-center(src="/images/variantes/Orda/Lancer.png") + +p. + El lancero es una pieza única "pseudo-híbrida" que se mueve y ataca + diferente. Se mueve como un caballo pero captura como una torre. + El lancero no es tan móvil como la torre, generalmente es más débil + que este último, especialmente en la final porque no puede cruzar + el tablero muy rápido. Su valor es comparable al del arquero. + +p. + Los lanceros eran uno de los dos componentes principales de la caballería + mongol, que opera como una caballería pesada. Aunque siendo más débil + que una torre, tienen la ventaja de poder ingresar al juego más rápido. + +h4 Evaluación de las piezas + +p. + Los valores precisos de las piezas son desconocidos. Sin embargo, aquí + están los valores utilizados por Fairy Stockfish. Estos son valores + genérico, no necesariamente específico del ajedrez Orda. + +table + tr + th Pieza del Reino + th Valor (inicio / fin) + th Pieza de la Horda + th Valor (inicio / fin) + tr + td Peón + td 120 / 213 + td Peón + td 120 / 213 + tr + td Dama + td 2538 / 2682 + td Yurta + td 630 / 630 + tr + td Alfil + td 825 / 915 + td Arquero + td 1100 / 1200 + tr + td Caballo + td 781 / 854 + td Kheshig + td 1600 / 1700 + tr + td Torre + td 1276 / 1380 + td Lancero + td 1050 / 1250 + +p + | Para aquellos que desean un enfoque simplificado, esta tabla puede ser + | usado como una aproximación. + span.italic Nota: esta simplificación es utilizada por el bot equivocada aquí. + +table + tr + th Pieza del Reino + th Valor + th Pieza de la Horda + th Valor + tr + td Peón + td 1 + td Peón + td 1 + tr + td Dama + td 9 + td Yurta + td 2 + tr + td Alfil + td 3 + td Arcquero + td 4 + tr + td Caballo + td 3 + td Kheshig + td 7 + tr + td Torre + td 5 + td Lancero + td 4 + +p. + En general, el ejército de la Horda es más débil que el Reino (en + basado solo en la evaluación de las piezas por Stockfish). + Sin embargo, la Horda comienza con peones en la tercera fila, que + debe equilibrar el juego. + +h3 Estrategia + +p. + La variante aún es joven, por lo que la estrategia aún no se ha escrito. + Gran parte de los datos actuales provienen de partes de la computadora. + La Horda no puede enrocarse, pero observamos que colocar el khan en f7 + en los primeros cuatro movimientos asegura igualmente al rey. + De hecho, Fairy Stockfish comienza con esta jugada en el 56% de los casos. + El resto es variable. + En cuanto al Reino, d4, g3 y b3 son las aperturas más frecuentes + en ese orden. diff --git a/client/src/translations/rules/Orda/fr.pug b/client/src/translations/rules/Orda/fr.pug new file mode 100644 index 00000000..742bf7ac --- /dev/null +++ b/client/src/translations/rules/Orda/fr.pug @@ -0,0 +1,266 @@ +p.boxed + | Le joueur en second dispose d'un jeu de pièces différent, + | se déplaçant en gros comme des "cavaliers augmentés". + +img.img-center(src="/images/variants/Orda/Orda.png") + +p + | Orda Chess est une variante inventée en 2020 par Couch Tomato + span.italic + | Note : il préfère rester anonyme :) En tout cas la version + | anglaise de ce texte et toutes les images sont de lui. + | L'idée pour ce jeu était d'obtenir un vrai combat asymétrique avec + | des armées différentes. Les variantes de Ralph Betza + a(href="https://www.chessvariants.com/unequal.dir/cwda.html") + | avec des armées différentes + | ont été une source d'inspiration, mais l'objectif était d'être en + | adéquation avec le thème présent. Dans notre cas, le thème de la + | nouvelle armée est le déplacement de cavalier : la plupart des pièces + | ont un élément évoquant le mouvement du cavalier. + | Étant donné ce "thème cavalier", cette variante a été construite + | d'après l'armée mongole et appelé la Horde. Une "orda" était une + | structure militaire pour les gens des steppes, et le mot français "horde" + | vient de là. L'armée originelle est appelée "le Royaume", pour le + | contraste. Le jeu en lui-même est incroyablement équilibré selon + | l'évaluation du module (en fait plus que pour les échecs standards), + | avec un ratio de gains proche de 50-50 pour le Royaume et la Horde. + +h3 Règles générales + +ol + li. + L'agencement des pièces est donné ci-dessus. Les pièces de la Horde sont + affichées en miroir des pièces standards, bien que les déplacements + soient différents. + li Le Royaume joue toujours le premier coup. + li La Horde ne peut pas roquer. + li. + Les pions de la Horde démarrant sur la troisième rangée, ils ne peuvent ni + avancer de deux cases ni être capturés en passant. Les pions du Royaume + quant à eux conservent ces deux options. + li Les seules promotions possibles sont en dame ou kheshig. + li. + Une nouvelle façon de gagner est possible : le "mat de camp". Ce "mat" + s'obtient en jouant le roi (sans être échec) sur la dernière rangée. + li Les autres règles s'appliquent, comme le pat ou la nulle par répétition. + +h3 Pièces de la Horde + +p. + Il y a quatre nouvelles unités uniques* à la Horde : 2 Lanciers, 2 Archers + à cheval, 2 Kheshigs et 1 Yourte (* à l'exception du kheshig que le + Royaume peut obtenir par promotion). Les kheshigs sont la pièce la plus + puissante (déplacement de cavalier + roi) et mènent chaque flanc, tandis + que la yourte est une pièce plutôt faible contrairement à la dame. + Le roi de la Horde est appelée Khan et a une allure différente, mais se + déplace et capture comme le roi du Royaume ; il est noté par la même + abbréviation (K) — le changement est purement esthétique et + thématique. + +p. + Le Lancier et l'Archer à cheval de la Horde sont uniques en le sens qu'ils + ne capturent pas comme ils se déplacent. Rappelez-vous que la Horde est + inspirée d'une cavalerie (militaire), et donc les Lanciers et Archers à + cheval se déplacent tous deux comme des cavaliers. Ils capturent comme + la tour et le fou, respectivement. Le Kheshig est plus traditionnel car il + capture comme il se déplace ; il combine les mouvements du roi et du + cavalier. La yourte capture également comme elle se déplace : comme un + général d'argent au Shogi. + +table + tr + th Pièce de la Horde + th "Contrepartie" du Royaume + th Déplacement + th Capture + tr + td Yourte + td Dame + td "Silver" + td "Silver" + tr + td Archer + td Fou + td Cavalier + td Fou + tr + td Kheshig + td Cavalier + td Cavalier+Roi + td Cavalier+Roi + tr + td Lancier + td Tour + td Cavalier + td Tour + +p. + Les détails et diagrammes de chaque pièce se trouvent ci-dessous. + Les points verts représentent les déplacements, les rouges les captures, + et les jaunes représentent les deux. + +h4 Yourte (Y) + +img.img-center(src="/images/variants/Orda/Yurt.png") + +p. + La yourte se déplace et capture d'une case en diagonale ou une case vers + l'avant. Cela correspond à un général d'argent au Shogi ou à un fou/khon + au Makruk. Il n'y a qu'une yourte, démarrant à l'emplacement de la dame, + mais contrairement à cette dernière elle correspond à une pièce (très) + mineure : la plus faible du jeu après le pion. Ceci dit, elle ne doit pas + être sous-estimée, car c'est une des rares pièces de la Horde qui capture + comme elle se déplace. Les deux autres sont le khan et le kheshig : les + deux pièces les plus précieuses. Ainsi la yourte a le rôle unique de + soutenir les pions et les autres pièces sans crainte de rebellion. + +p. + Une yourte est un habitat mobile pour les populations des steppes + asiatiques. Leur mobilité limitée contrastant avec leur importance pour + soutenir l'armée se reflète dans cette pièce. + +h4 Kheshig (H) + +img.img-center(src="/images/variants/Orda/Kheshig.png") + +p. + Le kheshig est une pièce hybride qui bouge et capture comme roi et cavalier + combinés. Ce type de pièce est aussi appelée centaure, de façon générique. + Le kheshig démarre à l'emplacmeent du cavalier, mais contrairement à ce + dernier c'est la pièce la plus puissante de la Horde. On peut l'imaginer + comme un général qui mènerait ses propres troupes sur chaque flanc. + On préfère généralement garder les kheshigs à l'abri en retrait pendant + l'ouverture jusqu'au milieu de jeu, à cause de leur extrême importance + pour la Horde en finale. + +p. + Les kheshigs étaient la garde impérial d'élite dans le royaume mongol. + Il est donc approprié qu'il soit incroyablement difficile pour le Royaume + de mater un khan sans éliminer au moins un des kheshigs. + +h4 Archer à cheval (A) + +img.img-center(src="/images/variants/Orda/Archer.png") + +p. + L'archer (à cheval) est une pièce unique "pseudo-hybride" qui se déplace + et capture différemment. L'archer dispose des mouvements du cavalier mais + capture comme un fou. L'archer évoluant à la fois sur cases noires et + blanches, il est plus fort que le fou du Royaume. + +p. + Les archers à cheval étaient l'une des deux composantes principales de la + cavalerie mongole, fonctionnant comme une cavalerie légère. Leur vitesse + et leur habileté faisaient d'eux une menace unique. Leur capacité à + se positionner rapidement pour une enfilade mortelle ou une fourchette + fait d'eux une dangeureuse menace pour le Royaume. + +h4 Lancier (L) + +img.img-center(src="/images/variants/Orda/Lancer.png") + +p. + Le lancier est une pièce unique "pseudo-hybride" qui se déplace et attaque + différemment. Il bouge comme un cavalier mais capture comme une tour. + Le lancier n'étant pas aussi mobile que la tour, il est généralement plus + faible que cette dernière, surtout en finale car il ne peut pas traverser + l'échiquier très vite. Sa valeur est comparable à celle de l'archer. + +p. + Les lanciers étaient l'une des deux composantes principales de la cavalerie + mongole, fonctionnant comme une cavalerie lourde. Bien qu'étant plus faibles + qu'une tour, ils ont l'avantage de pouvoir entrer dans le jeu plus vite. + +h4 Évaluation des pièces + +p. + Les valeurs précises des pièces sont inconnues. Cependant, voici les + valeurs utilisées par Fairy Stockfish. Celles-ci sont des valeurs + génériques, pas nécessairement spécifiques aux échecs Orda. + +table + tr + th Pièce du royaume + th Valeur (Début / Fin) + th Pièce de la Horde + th Value (Début / Fin) + tr + td Pion + td 120 / 213 + td Pion + td 120 / 213 + tr + td Dame + td 2538 / 2682 + td Yourte + td 630 / 630 + tr + td Fou + td 825 / 915 + td Archer + td 1100 / 1200 + tr + td Cavalier + td 781 / 854 + td Kheshig + td 1600 / 1700 + tr + td Tour + td 1276 / 1380 + td Lancier + td 1050 / 1250 + +p + | Pour ceux souhaitant une approche simplifiée, cette table peut être + | utilisée comme approximation. + span.note Note : cette simplification est utilisée par le mauvais bot ici. + +table + tr + th Pièce du Royaume + th Valeur + th Pièce de la Horde + th Valeur + tr + td Pion + td 1 + td Pion + td 1 + tr + td Dame + td 9 + td Yourte + td 2 + tr + td Fou + td 3 + td Archer + td 4 + tr + td Cavalier + td 3 + td Kheshig + td 7 + tr + td Tour + td 5 + td Lancier + td 4 + +p. + Globalement, l'armée de la Horde est plus faible que le Royaume (en se + basant sur la seule évaluation des pièces par Stockfish). + La Horde démarre cependant avec des pions sur la troisème rangée, ce qui + devrait équilibrer le jeu. + +h3 Stratégie + +p. + La variante est encore jeune, donc la stratégie reste à écrire ! + Beaucoup des données actuelles proviennent de parties de l'ordinateur. + La Horde ne peut pas roquer, mais on observe que placer le khan en f7 + dans les quatre premiers coups met le roi en sécurité de manière similaire. + En fait, Fairy Stockfish commence par ce coup dans 56% des cas. + Le reste est variable. + Concernant le Royaume, d4, g3 et b3 sont les ouvertures les plus fréquentes + dans cet ordre. diff --git a/client/src/variants/Dynamo.js b/client/src/variants/Dynamo.js index c76c040b..4ec1927c 100644 --- a/client/src/variants/Dynamo.js +++ b/client/src/variants/Dynamo.js @@ -1,5 +1,97 @@ import { ChessRules } from "@/base_rules"; export class DynamoRules extends ChessRules { - // TODO + canIplay(side, [x, y]) { + // Sometimes opponent's pieces can be moved directly + return true; + } + + // NOTE: to push a piece out of the board, make it slide until our piece + // (doing the action, moving or not) + getPotentialMovesFrom([x, y]) { + const color = this.turn; + let moves = []; + if (this.getColor(x, y) != color) { + // Push or pull something: freely only if subTurn == 1 + if (this.subTurn == 2) { + // I know that someone is pushing/pulling: find out who, + // and deduce my possible squares (or exit). + // TODO + } else { + // Look in every direction for a friendly pusher/puller. + // This means that the action is done without moving. + // TODO + } + } else { + // My piece: fill first with normal moves (if any), + // and add pushes/pulls (if any). + // TODO + } + } + + getPPpath(m) { + let imgName = ""; + if (m.vanish.length == 1) imgName = "empty"; + else { + // Something is pushed or pull: count by how many squares + if (m.appear.length == 1) + // It just exit the board + imgName = "raus"; + else { + const deltaX = Math.abs(m.appear[1].x - m.vanish[1].x); + const deltaY = Math.abs(m.appear[1].y - m.vanish[1].y); + if (deltaX == 0) imgName = "shift" + deltaY; + else if (deltaY == 0) imgName = "shift" + deltaX; + else + // Special knight push/pull: just print "P" + imgName = "pstep"; + } + } + return "Dynamo/" + imgName; + } + + isAttackedBySlideNJump([x, y], color, piece, steps, oneStep) { + for (let step of steps) { + let rx = x + step[0], + ry = y + step[1]; + while (V.OnBoard(rx, ry) && this.board[rx][ry] == V.EMPTY && !oneStep) { + rx += step[0]; + ry += step[1]; + } + if ( + V.OnBoard(rx, ry) && + this.getPiece(rx, ry) == piece && + this.getColor(rx, ry) == color + ) { + // Now step in the other direction: if end of the world, then attacked + rx = x - step[0]; + ry = y - step[1]; + while (V.OnBoard(rx, ry) && this.board[rx][ry] == V.EMPTY && !oneStep) { + rx -= step[0]; + ry -= step[1]; + } + if (!V.OnBoard(rx, ry)) return true; + } + } + return false; + } + + isAttackedByPawn([x, y], color) { + const lastRank = (color == 'w' ? 0 : 7); + if (y != lastRank) + // The king can be pushed out by a pawn only on last rank + return false; + const pawnShift = (color == "w" ? 1 : -1); + 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; + } }; diff --git a/client/src/variants/Eightpieces.js b/client/src/variants/Eightpieces.js index fa80824b..0f335184 100644 --- a/client/src/variants/Eightpieces.js +++ b/client/src/variants/Eightpieces.js @@ -83,8 +83,15 @@ export class EightpiecesRules extends ChessRules { return "Eightpieces/tmp_png/" + b; } - getPPpath(b, orientation) { - return this.getPpath(b, null, null, orientation); + getPPpath(m, orientation) { + return ( + this.getPpath( + m.appear[0].c + m.appear[0].p, + null, + null, + orientation + ) + ); } static ParseFen(fen) { diff --git a/client/src/variants/Orda.js b/client/src/variants/Orda.js new file mode 100644 index 00000000..4d911f40 --- /dev/null +++ b/client/src/variants/Orda.js @@ -0,0 +1,323 @@ +import { ChessRules } from "@/base_rules"; +import { ArrayFun } from "@/utils/array"; +import { randInt } from "@/utils/alea"; + +export class OrdaRules extends ChessRules { + static get PawnSpecs() { + return Object.assign( + {}, + ChessRules.PawnSpecs, + { promotions: [V.QUEEN, V.KHESHIG] } + ); + } + + static IsGoodFlags(flags) { + // Only white can castle + return !!flags.match(/^[a-z]{2,2}$/); + } + + getPpath(b) { + if (b[0] == 'b' || b[1] == 'h') + // Horde piece or white promoted pawn in kheshig + return "Orda/" + b; + return b; + } + + static GenRandInitFen(randomness) { + if (randomness == 0) + return "lhaykahl/8/pppppppp/8/8/8/PPPPPPPP/RNBQKBNR w 0 ah -"; + + // Mapping kingdom --> horde: + const piecesMap = { + 'r': 'l', + 'n': 'h', + 'b': 'a', + 'q': 'y', + 'k': 'k' + }; + + let pieces = { w: new Array(8), b: new Array(8) }; + let flags = ""; + // Shuffle pieces on first (and last rank if randomness == 2) + for (let c of ["w", "b"]) { + if (c == 'b' && randomness == 1) { + pieces['b'] = pieces['w'].map(p => piecesMap[p]); + break; + } + + // TODO: same code as in base_rules. Should extract and factorize? + + let positions = ArrayFun.range(8); + + let randIndex = 2 * randInt(4); + const bishop1Pos = positions[randIndex]; + let randIndex_tmp = 2 * randInt(4) + 1; + const bishop2Pos = positions[randIndex_tmp]; + positions.splice(Math.max(randIndex, randIndex_tmp), 1); + positions.splice(Math.min(randIndex, randIndex_tmp), 1); + + randIndex = randInt(6); + const knight1Pos = positions[randIndex]; + positions.splice(randIndex, 1); + randIndex = randInt(5); + const knight2Pos = positions[randIndex]; + positions.splice(randIndex, 1); + + randIndex = randInt(4); + const queenPos = positions[randIndex]; + positions.splice(randIndex, 1); + + const rook1Pos = positions[0]; + const kingPos = positions[1]; + const rook2Pos = positions[2]; + + pieces[c][rook1Pos] = "r"; + pieces[c][knight1Pos] = "n"; + pieces[c][bishop1Pos] = "b"; + pieces[c][queenPos] = "q"; + pieces[c][kingPos] = "k"; + pieces[c][bishop2Pos] = "b"; + pieces[c][knight2Pos] = "n"; + pieces[c][rook2Pos] = "r"; + if (c == 'b') pieces[c] = pieces[c].map(p => piecesMap[p]); + else flags = V.CoordToColumn(rook1Pos) + V.CoordToColumn(rook2Pos); + } + // Add turn + flags + enpassant + return ( + pieces["b"].join("") + + "/8/pppppppp/8/8/8/PPPPPPPP/" + + pieces["w"].join("").toUpperCase() + + " w 0 " + flags + " -" + ); + } + + getFlagsFen() { + return this.castleFlags['w'].map(V.CoordToColumn).join(""); + } + + setFlags(fenflags) { + this.castleFlags = { 'w': [-1, -1] }; + for (let i = 0; i < 2; i++) + this.castleFlags['w'][i] = V.ColumnToCoord(fenflags.charAt(i)); + } + + static get LANCER() { + return 'l'; + } + static get ARCHER() { + return 'a'; + } + static get KHESHIG() { + return 'h'; + } + static get YURT() { + return 'y'; + } + // Khan is technically a King, so let's keep things simple. + + static get PIECES() { + return ChessRules.PIECES.concat([V.LANCER, V.ARCHER, V.KHESHIG, V.YURT]); + } + + getPotentialMovesFrom([x, y]) { + switch (this.getPiece(x, y)) { + case V.LANCER: + return this.getPotentialLancerMoves([x, y]); + case V.ARCHER: + return this.getPotentialArcherMoves([x, y]); + case V.KHESHIG: + return this.getPotentialKheshigMoves([x, y]); + case V.YURT: + return this.getPotentialYurtMoves([x, y]); + default: + return super.getPotentialMovesFrom([x, y]); + } + return []; + } + + getSlideNJumpMoves([x, y], steps, oneStep, options) { + options = options || {}; + let moves = []; + outerLoop: for (let step of steps) { + let i = x + step[0]; + let j = y + step[1]; + while (V.OnBoard(i, j) && this.board[i][j] == V.EMPTY) { + if (!options.onlyTake) moves.push(this.getBasicMove([x, y], [i, j])); + if (oneStep) continue outerLoop; + i += step[0]; + j += step[1]; + } + if (V.OnBoard(i, j) && this.canTake([x, y], [i, j]) && !options.onlyMove) + moves.push(this.getBasicMove([x, y], [i, j])); + } + return moves; + } + + getPotentialLancerMoves(sq) { + const onlyMoves = this.getSlideNJumpMoves( + sq, + V.steps[V.KNIGHT], + "oneStep", + { onlyMove: true } + ); + const onlyTakes = this.getSlideNJumpMoves( + sq, + V.steps[V.ROOK], + null, + { onlyTake: true } + ); + return onlyMoves.concat(onlyTakes); + } + + getPotentialArcherMoves(sq) { + const onlyMoves = this.getSlideNJumpMoves( + sq, + V.steps[V.KNIGHT], + "oneStep", + { onlyMove: true } + ); + const onlyTakes = this.getSlideNJumpMoves( + sq, + V.steps[V.BISHOP], + null, + { onlyTake: true } + ); + return onlyMoves.concat(onlyTakes); + } + + getPotentialLancerMoves(sq) { + const onlyMoves = this.getSlideNJumpMoves( + sq, + V.steps[V.KNIGHT], + "oneStep", + { onlyMove: true } + ); + const onlyTakes = this.getSlideNJumpMoves( + sq, + V.steps[V.ROOK], + null, + { onlyTake: true } + ); + return onlyMoves.concat(onlyTakes); + } + + getPotentialKheshigMoves(sq) { + return this.getSlideNJumpMoves( + sq, + V.steps[V.KNIGHT].concat(V.steps[V.ROOK]).concat(V.steps[V.BISHOP]), + "oneStep" + ); + } + + getPotentialYurtMoves(sq) { + return this.getSlideNJumpMoves( + sq, + V.steps[V.BISHOP].concat([1, 0]), + "oneSTep" + ); + } + + getPotentialKingMoves([x, y]) { + if (this.getColor(x, y) == 'w') return super.getPotentialKingMoves([x, y]); + // Horde doesn't castle: + return this.getSlideNJumpMoves( + [x, y], + V.steps[V.ROOK].concat(V.steps[V.BISHOP]), + "oneStep" + ); + } + + isAttacked(sq, color) { + if (color == 'w') { + return ( + super.isAttacked(sq, color) || + this.isAttackedByKheshig(sq, color) + ); + } + // Horde: only pawn and queen (if promotions) in common: + return ( + super.isAttackedByPawn(sq, color) || + this.isAttackedByLancer(sq, color) || + this.isAttackedByKheshig(sq, color) || + this.isAttackedByArcher(sq, color) || + this.isAttackedByYurt(sq, color) || + super.isAttackedByQueen(sq, color) + ); + } + + isAttackedByLancer(sq, color) { + return this.isAttackedBySlideNJump(sq, color, V.LANCER, V.steps[V.ROOK]); + } + + isAttackedByArcher(sq, color) { + return this.isAttackedBySlideNJump(sq, color, V.ARCHER, V.steps[V.BISHOP]); + } + + isAttackedByKheshig(sq, color) { + return super.isAttackedBySlideNJump( + sq, + color, + V.KHESHIG, + V.steps[V.KNIGHT].concat(V.steps[V.ROOK]).concat(V.steps[V.BISHOP]), + "oneStep" + ); + } + + isAttackedByYurt(sq, color) { + return super.isAttackedBySlideNJump( + sq, + color, + V.YURT, + V.steps[V.BISHOP].concat([1, 0]), + "oneStep" + ); + } + + updateCastleFlags(move, piece) { + // Only white can castle: + const firstRank = 7; + if (piece == V.KING && move.appear[0].c == 'w') + this.castleFlags['w'] = [8, 8]; + else if ( + move.start.x == firstRank && + this.castleFlags['w'].includes(move.start.y) + ) { + const flagIdx = (move.start.y == this.castleFlags['w'][0] ? 0 : 1); + this.castleFlags['w'][flagIdx] = 8; + } + else if ( + move.end.x == firstRank && + this.castleFlags['w'].includes(move.end.y) + ) { + const flagIdx = (move.end.y == this.castleFlags['w'][0] ? 0 : 1); + this.castleFlags['w'][flagIdx] = 8; + } + } + + getCurrentScore() { + // Turn has changed: + const color = V.GetOppCol(this.turn); + const lastRank = (color == 'w' ? 0 : 7); + if (this.kingPos[color][0] == lastRank) + // The opposing edge is reached! + return color == "w" ? "1-0" : "0-1"; + if (this.atLeastOneMove()) return "*"; + // Game over + const oppCol = this.turn; + if (!this.underCheck(oppCol)) return "1/2"; + return (oppCol == "w" ? "0-1" : "1-0"); + } + + static get VALUES() { + return Object.assign( + {}, + ChessRules.VALUES, + { + y: 2, + a: 4, + h: 7, + l: 4 + } + ); + } +}; diff --git a/client/src/views/Game.vue b/client/src/views/Game.vue index e5b45ecd..f9bc8430 100644 --- a/client/src/views/Game.vue +++ b/client/src/views/Game.vue @@ -629,8 +629,13 @@ export default { this.send("fullgame", { data: gameToSend, target: data.from }); break; case "fullgame": - // Callback "roomInit" to poll clients only after game is loaded - this.loadVariantThenGame(data.data, this.roomInit); + if (!!data.data.empty) { + alert(this.st.tr["The game should be in another tab"]); + this.$router.go(-1); + } + else + // Callback "roomInit" to poll clients only after game is loaded + this.loadVariantThenGame(data.data, this.roomInit); break; case "asklastate": // Sending informative last state if I played a move or score != "*" diff --git a/client/src/views/Rules.vue b/client/src/views/Rules.vue index 48a9e935..127d1db7 100644 --- a/client/src/views/Rules.vue +++ b/client/src/views/Rules.vue @@ -26,6 +26,7 @@ main | {{ st.tr["Analysis mode"] }} .row .col-sm-12.col-md-8.col-md-offset-2.col-lg-6.col-lg-offset-3 + h4#variantName {{ gameInfo.vname }} div( v-show="display=='rules'" v-html="content" @@ -169,6 +170,10 @@ export default { background-color: lightgrey font-weight: bold +h4#variantName + text-align: center + font-weight: bold + figure.diagram-container margin: 15px 0 15px 0 text-align: center @@ -235,4 +240,14 @@ ul:not(.browser-default) ul:not(.browser-default) > li list-style-type: disc + +table + margin: 15px auto + +.italic + font-style: italic + +img.img-center + display: block + margin: 0 auto 15px auto diff --git a/server/db/populate.sql b/server/db/populate.sql index 18957773..52c043cb 100644 --- a/server/db/populate.sql +++ b/server/db/populate.sql @@ -24,6 +24,7 @@ insert or ignore into Variants (name,description) values ('Cylinder', 'Neverending rows'), ('Dark', 'In the shadow'), ('Doublearmy', '64 pieces on the board'), + ('Dynamo', 'Push and pull'), ('Eightpieces', 'Each piece is unique'), ('Enpassant', 'Capture en passant'), ('Extinction', 'Capture all of a kind'), @@ -37,6 +38,7 @@ insert or ignore into Variants (name,description) values ('Losers', 'Get strong at self-mate'), ('Magnetic', 'Laws of attraction'), ('Marseille', 'Move twice'), + ('Orda', 'Mongolian Horde'), ('Parachute', 'Landing on the board'), ('Perfect', 'Powerful pieces'), ('Racingkings', 'Kings cross the 8x8 board'), diff --git a/server/sockets.js b/server/sockets.js index 25abadb7..d00b3c89 100644 --- a/server/sockets.js +++ b/server/sockets.js @@ -209,6 +209,9 @@ module.exports = function(wss) { clients[page][rid][rtmpId].socket, { code: "askfullgame", from: [sid,tmpId] } ); + } else { + // I'm the only person who have the game for the moment: + send(socket, { code: "fullgame", data: { empty: true } }); } } break; -- 2.44.0