From: Benjamin Auder Date: Sun, 10 Jan 2021 20:30:37 +0000 (+0100) Subject: Add Alapo, Crossing, Kingsmaker, Squatter variants X-Git-Url: https://git.auder.net/js/doc/%7B%7B%20targetUrl%20%7D%7D?a=commitdiff_plain;h=0f7762c1d87e21d1c13ff0f38bd234b64b0a29d9;p=vchess.git Add Alapo, Crossing, Kingsmaker, Squatter variants --- diff --git a/TODO b/TODO index ec1571b9..a6d77bf4 100644 --- a/TODO +++ b/TODO @@ -3,24 +3,22 @@ Embedded rules language not updated when language is set (in Analyse, Game and P If new live game starts in background, "new game" notify OK but not first move. NEW VARIANTS: -Squatter Chess: safe on last rank = win -Crossing Chess = win when the king cross half-board -Kingmaker: pawns can promote also into enemy king ---> no king tracking, getCheckSquares + underCheck test all kings - -https://boardgamegeek.com/boardgame/18661/alapo -Alapo is a strategy game. Each player owns twelve abstract pieces, two each of six different kinds. Round pieces move in any of the eight directions on the 6 by 6 board; square pieces move only orthogonally and triangular pieces only diagonally. Large pieces move any distance, small pieces only one field per turn. -Opponent pieces can be eliminated by moving onto their position. The goal is to reach the opponent's base line with one of your pieces without the opponent being able to eliminate your piece in his/her next move. - https://www.chessvariants.com/mvopponent.dir/hypnotic-chess.html https://www.chessvariants.com/mvopponent.dir/mesmer-chess.html https://www.reddit.com/r/TotemChess/comments/imi3v7/totem_rules/ +--> replaced by "Joker" chess --> start on bishop of our color (instead), + moves like a Bishop + Dabbabah, can swap with a piece *on same color* (as a move) at anytime. hmm + or rather: start as in Antiking + Mesmer, in front of. moves like an amazon. swap with any color. better! http://history.chess.free.fr/rollerball.htm + https://www.chessvariants.com/40.dir/rollerball/index.html +https://www.pychess.org/variant/shogun https://www.chessvariants.com/other.dir/fugue.html https://www.chessvariants.com/rules/spartan-chess https://www.chessvariants.com/incinf.dir/bario.html -https://www.pychess.org/variant/shogun + https://www.chessvariants.com/index/listcomments.php?order=DESC&itemid=Bario + https://www.bario-chess-checkers-chessphotography-spaceart.de/ + https://le-cdn.website-editor.net/20ef5f800ea646c29f6852cfc5ceda07/dms3rep/multi/opt/BAR028-e15a849c-960w.jpg https://musketeerchess.net/games/musketeer/index.php Attention règle de promotion + SVG / PNG https://musketeerchess.net/games/cerebral/rules/rules.php : from Titan, should be easy diff --git a/client/public/images/pieces/Alapo/bb.svg b/client/public/images/pieces/Alapo/bb.svg new file mode 100644 index 00000000..939ba3af --- /dev/null +++ b/client/public/images/pieces/Alapo/bb.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/client/public/images/pieces/Alapo/bbi.svg b/client/public/images/pieces/Alapo/bbi.svg new file mode 100644 index 00000000..fb3c955f --- /dev/null +++ b/client/public/images/pieces/Alapo/bbi.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/client/public/images/pieces/Alapo/bc.svg b/client/public/images/pieces/Alapo/bc.svg new file mode 100644 index 00000000..8c531b51 --- /dev/null +++ b/client/public/images/pieces/Alapo/bc.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/client/public/images/pieces/Alapo/bci.svg b/client/public/images/pieces/Alapo/bci.svg new file mode 100644 index 00000000..e9afcea9 --- /dev/null +++ b/client/public/images/pieces/Alapo/bci.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/client/public/images/pieces/Alapo/bq.svg b/client/public/images/pieces/Alapo/bq.svg new file mode 100644 index 00000000..7948061e --- /dev/null +++ b/client/public/images/pieces/Alapo/bq.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/client/public/images/pieces/Alapo/bqi.svg b/client/public/images/pieces/Alapo/bqi.svg new file mode 120000 index 00000000..a76b86f9 --- /dev/null +++ b/client/public/images/pieces/Alapo/bqi.svg @@ -0,0 +1 @@ +bq.svg \ No newline at end of file diff --git a/client/public/images/pieces/Alapo/br.svg b/client/public/images/pieces/Alapo/br.svg new file mode 100644 index 00000000..fdd99216 --- /dev/null +++ b/client/public/images/pieces/Alapo/br.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/client/public/images/pieces/Alapo/bri.svg b/client/public/images/pieces/Alapo/bri.svg new file mode 120000 index 00000000..74cce667 --- /dev/null +++ b/client/public/images/pieces/Alapo/bri.svg @@ -0,0 +1 @@ +br.svg \ No newline at end of file diff --git a/client/public/images/pieces/Alapo/bs.svg b/client/public/images/pieces/Alapo/bs.svg new file mode 100644 index 00000000..8cd85d91 --- /dev/null +++ b/client/public/images/pieces/Alapo/bs.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/client/public/images/pieces/Alapo/bsi.svg b/client/public/images/pieces/Alapo/bsi.svg new file mode 120000 index 00000000..4ab8f86b --- /dev/null +++ b/client/public/images/pieces/Alapo/bsi.svg @@ -0,0 +1 @@ +bs.svg \ No newline at end of file diff --git a/client/public/images/pieces/Alapo/bt.svg b/client/public/images/pieces/Alapo/bt.svg new file mode 100644 index 00000000..3e86c705 --- /dev/null +++ b/client/public/images/pieces/Alapo/bt.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/client/public/images/pieces/Alapo/bti.svg b/client/public/images/pieces/Alapo/bti.svg new file mode 120000 index 00000000..5340f27b --- /dev/null +++ b/client/public/images/pieces/Alapo/bti.svg @@ -0,0 +1 @@ +bt.svg \ No newline at end of file diff --git a/client/public/images/pieces/Alapo/wb.svg b/client/public/images/pieces/Alapo/wb.svg new file mode 100644 index 00000000..411ec2f2 --- /dev/null +++ b/client/public/images/pieces/Alapo/wb.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/client/public/images/pieces/Alapo/wbi.svg b/client/public/images/pieces/Alapo/wbi.svg new file mode 100644 index 00000000..61733b15 --- /dev/null +++ b/client/public/images/pieces/Alapo/wbi.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/client/public/images/pieces/Alapo/wc.svg b/client/public/images/pieces/Alapo/wc.svg new file mode 100644 index 00000000..abad0f9c --- /dev/null +++ b/client/public/images/pieces/Alapo/wc.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/client/public/images/pieces/Alapo/wci.svg b/client/public/images/pieces/Alapo/wci.svg new file mode 100644 index 00000000..4791916a --- /dev/null +++ b/client/public/images/pieces/Alapo/wci.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/client/public/images/pieces/Alapo/wq.svg b/client/public/images/pieces/Alapo/wq.svg new file mode 100644 index 00000000..af99afaf --- /dev/null +++ b/client/public/images/pieces/Alapo/wq.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/client/public/images/pieces/Alapo/wqi.svg b/client/public/images/pieces/Alapo/wqi.svg new file mode 120000 index 00000000..7ae9b2d6 --- /dev/null +++ b/client/public/images/pieces/Alapo/wqi.svg @@ -0,0 +1 @@ +wq.svg \ No newline at end of file diff --git a/client/public/images/pieces/Alapo/wr.svg b/client/public/images/pieces/Alapo/wr.svg new file mode 100644 index 00000000..716a8e56 --- /dev/null +++ b/client/public/images/pieces/Alapo/wr.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/client/public/images/pieces/Alapo/wri.svg b/client/public/images/pieces/Alapo/wri.svg new file mode 120000 index 00000000..3f766fa3 --- /dev/null +++ b/client/public/images/pieces/Alapo/wri.svg @@ -0,0 +1 @@ +wr.svg \ No newline at end of file diff --git a/client/public/images/pieces/Alapo/ws.svg b/client/public/images/pieces/Alapo/ws.svg new file mode 100644 index 00000000..f5f19cfc --- /dev/null +++ b/client/public/images/pieces/Alapo/ws.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/client/public/images/pieces/Alapo/wsi.svg b/client/public/images/pieces/Alapo/wsi.svg new file mode 120000 index 00000000..f1c400f5 --- /dev/null +++ b/client/public/images/pieces/Alapo/wsi.svg @@ -0,0 +1 @@ +ws.svg \ No newline at end of file diff --git a/client/public/images/pieces/Alapo/wt.svg b/client/public/images/pieces/Alapo/wt.svg new file mode 100644 index 00000000..9c7e4e72 --- /dev/null +++ b/client/public/images/pieces/Alapo/wt.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/client/public/images/pieces/Alapo/wti.svg b/client/public/images/pieces/Alapo/wti.svg new file mode 120000 index 00000000..7e0ea5d3 --- /dev/null +++ b/client/public/images/pieces/Alapo/wti.svg @@ -0,0 +1 @@ +wt.svg \ No newline at end of file diff --git a/client/src/styles/_board_squares_img.sass b/client/src/styles/_board_squares_img.sass index 19916286..e39290d7 100644 --- a/client/src/styles/_board_squares_img.sass +++ b/client/src/styles/_board_squares_img.sass @@ -15,6 +15,10 @@ div.board5 width: 20% padding-bottom: 20% +div.board6 + width: 16.66% + padding-bottom: 16.66% + div.board7 width: 14.28% padding-bottom: 14.28% diff --git a/client/src/translations/en.js b/client/src/translations/en.js index 5f8d341f..41683bd1 100644 --- a/client/src/translations/en.js +++ b/client/src/translations/en.js @@ -191,6 +191,7 @@ export const translations = { "Chinese Chess": "Chinese Chess", "Convert & support (v1)": "Convert & support (v1)", "Convert & support (v2)": "Convert & support (v2)", + "Cross the river": "Cross the river", "Dance with the King": "Dance with the King", "Dangerous captures": "Dangerous captures", "Dangerous collisions": "Dangerous collisions", @@ -211,6 +212,7 @@ export const translations = { "Friendly pieces": "Friendly pieces", "In the shadow": "In the shadow", "Interweaved colorbound teams": "Interweaved colorbound teams", + "Geometric Chess": "Geometric Chess", "Get strong at self-mate": "Get strong at self-mate", "Give three checks": "Give three checks", "Harassed kings": "Harassed kings", @@ -262,6 +264,7 @@ export const translations = { "Play opponent's pieces": "Play opponent's pieces", "Powerful pieces": "Powerful pieces", "Prolongated captures": "Prolongated captures", + "Promote into kings": "Promote into kings", "Protect your pawns": "Protect your pawns", "Push and pull": "Push and pull", "Queen disguised as a pawn": "Queen disguised as a pawn", @@ -282,6 +285,7 @@ export const translations = { "Shogi 5 x 5": "Shogi 5 x 5", "Shoot pieces": "Shoot pieces", "Squares disappear": "Squares disappear", + "Squat last rank": "Squat last rank", "Standard rules": "Standard rules", "Stun & kick pieces": "Stun & kick pieces", "Thai Chess (v1)": "Thai Chess (v1)", diff --git a/client/src/translations/es.js b/client/src/translations/es.js index be0974aa..14d67eba 100644 --- a/client/src/translations/es.js +++ b/client/src/translations/es.js @@ -191,6 +191,7 @@ export const translations = { "Chinese Chess": "Ajedrez chino", "Convert & support (v1)": "Convertir & apoyar (v1)", "Convert & support (v2)": "Convertir & apoyar (v2)", + "Cross the river": "Cruza el río", "Dance with the King": "Baila con el Rey", "Dangerous captures": "Capturas peligrosas", "Dangerous collisions": "Colisiones peligrosas", @@ -211,6 +212,7 @@ export const translations = { "Friendly pieces": "Piezas amistosas", "In the shadow": "En la sombra", "Interweaved colorbound teams": "Equipos unicolores entrelazados", + "Geometric Chess": "Ajedrez geométrico", "Get strong at self-mate": "Progreso en mates asistidos", "Give three checks": "Dar tres jaques", "Harassed kings": "Reyes acosados", @@ -262,6 +264,7 @@ export const translations = { "Play opponent's pieces": "Jugar piezas opuestas", "Powerful pieces": "Piezas poderosas", "Prolongated captures": "Capturas extendidas", + "Promote into kings": "Promociones en reyes", "Protect your pawns": "Protege tus peones", "Push and pull": "Empujar y tirar", "Queen disguised as a pawn": "Reina disfrazada de peón", @@ -282,6 +285,7 @@ export const translations = { "Shogi 5 x 5": "Shogi 5 x 5", "Shoot pieces": "Tirar de las piezas", "Squares disappear": "Las casillas desaparecen", + "Squat last rank": "Ocupa la última fila", "Standard rules": "Reglas estandar", "Stun & kick pieces": "Aturdir & patear piezas", "Thai Chess (v1)": "Ajedrez tailandés (v1)", diff --git a/client/src/translations/fr.js b/client/src/translations/fr.js index 4b6a2f77..255595ec 100644 --- a/client/src/translations/fr.js +++ b/client/src/translations/fr.js @@ -191,6 +191,7 @@ export const translations = { "Chinese Chess": "Échecs chinois", "Convert & support (v1)": "Convertir & soutenir (v1)", "Convert & support (v2)": "Convertir & soutenir (v2)", + "Cross the river": "Traversez la rivière", "Dance with the King": "Dansez avec le Roi", "Dangerous captures": "Captures dangeureuses", "Dangerous collisions": "Collisions dangeureuses", @@ -211,6 +212,7 @@ export const translations = { "Friendly pieces": "Pièces amies", "In the shadow": "Dans l'ombre", "Interweaved colorbound teams": "Équipes unicolores entremêlées", + "Geometric Chess": "Échecs géométriques", "Get strong at self-mate": "Progressez en mats aidés", "Give three checks": "Donnez trois échecs", "Harassed kings": "Rois harcelés", @@ -262,6 +264,7 @@ export const translations = { "Play opponent's pieces": "Jouez les pièces adverses", "Powerful pieces": "Pièces puissantes", "Prolongated captures": "Captures prolongées", + "Promote into kings": "Promotions en rois", "Protect your pawns": "Protégez vos pions", "Push and pull": "Pousser et tirer", "Queen disguised as a pawn": "Reine déguisée en pion", @@ -282,6 +285,7 @@ export const translations = { "Shogi 5 x 5": "Shogi 5 x 5", "Shoot pieces": "Tirez sur les pièces", "Squares disappear": "Les cases disparaissent", + "Squat last rank": "Occupez la dernière rangée", "Standard rules": "Règles usuelles", "Stun & kick pieces": "Étourdissez & frappez les pièces", "Thai Chess": "Échecs thai", diff --git a/client/src/translations/rules/Alapo/en.pug b/client/src/translations/rules/Alapo/en.pug new file mode 100644 index 00000000..9a1d0237 --- /dev/null +++ b/client/src/translations/rules/Alapo/en.pug @@ -0,0 +1,28 @@ +p.boxed + | Win by being safe on last rank. + +p. + Each player owns twelve abstract pieces, two each of six different kinds. + Round pieces move in any direction; + square pieces move only orthogonally and triangular pieces only diagonally. + Large pieces move any distance, small pieces only one field per turn. + +figure.diagram-container + .diagram + | fen:rbqqbr/tcssct/6/6/TCSSCT/RBQQBR: + figcaption Deterministic initial position. + +p. + Opponent pieces can be eliminated by moving onto their position. + The goal is to reach the opponent's base line with one of your pieces, + safe from captures. + +h3 More information + +p + | See Alapo pages on + a(href="https://boardgamegeek.com/boardgame/18661/alapo") boardgamegeek.com + |  and + a(href="https://www.chessvariants.com/small.dir/alapo.html") + | chessvariants.com + | . diff --git a/client/src/translations/rules/Alapo/es.pug b/client/src/translations/rules/Alapo/es.pug new file mode 100644 index 00000000..3fcccc54 --- /dev/null +++ b/client/src/translations/rules/Alapo/es.pug @@ -0,0 +1,30 @@ +p.boxed + | Gana llegando a salvo a la última fila. + +p. + Cada jugador tiene doce piezas abstractas, dos de cada uno de seis tipos + diferentes. Las piezas redondas se mueven en cualquier dirección; + las piezas cuadradas evolucionan ortogonalmente mientras que los triángulos + moverse en diagonal. + Las piezas grandes se mueven tan lejos como quieran, + los pequeños están limitados a un espacio por turno. + +figure.diagram-container + .diagram + | fen:rbqqbr/tcssct/6/6/TCSSCT/RBQQBR: + figcaption Posición inicial determinista. + +p. + Las piezas opuestas se eliminan moviéndose a su posición. + El objetivo es llegar a la primera fila contraria con + una de sus piezas, a salvo de la captura. + +h3 Más información + +p + | Consulte las páginas sobre Alapo en + a(href="https://boardgamegeek.com/boardgame/18661/alapo") boardgamegeek.com + |  y + a(href="https://www.chessvariants.com/small.dir/alapo.html") + | chessvariants.com + | . diff --git a/client/src/translations/rules/Alapo/fr.pug b/client/src/translations/rules/Alapo/fr.pug new file mode 100644 index 00000000..25200cce --- /dev/null +++ b/client/src/translations/rules/Alapo/fr.pug @@ -0,0 +1,30 @@ +p.boxed + | Gagnez en arrivant en sécurité sur la dernière rangée. + +p. + Chaque joueur possède douze pièces abstraites, deux de chaque de six types + différents. Les pièces rondes se déplacent dans n'importe quelle direction ; + les pièces carrées évoluent orthogonalement tandis que les triangles + avancent en diagonale. + Les grandes pièces se déplacent aussi loin qu'elle veulent, + les petites étant limitées à une case par tour. + +figure.diagram-container + .diagram + | fen:rbqqbr/tcssct/6/6/TCSSCT/RBQQBR: + figcaption Position initiale déterministe. + +p. + Les pièces adverses sont éliminées en se déplaçant sur leur position. + L'objectif est d'atteindre la première rangée adverse avec + une de vos pièces, à l'abri des captures. + +h3 Plus d'information + +p + | Voir les pages au sujet d'Alapo sur + a(href="https://boardgamegeek.com/boardgame/18661/alapo") boardgamegeek.com + |  et + a(href="https://www.chessvariants.com/small.dir/alapo.html") + | chessvariants.com + | . diff --git a/client/src/translations/rules/Bario/en.pug b/client/src/translations/rules/Bario/en.pug new file mode 100644 index 00000000..21203baa --- /dev/null +++ b/client/src/translations/rules/Bario/en.pug @@ -0,0 +1 @@ +p.boxed TODO diff --git a/client/src/translations/rules/Bario/es.pug b/client/src/translations/rules/Bario/es.pug new file mode 100644 index 00000000..21203baa --- /dev/null +++ b/client/src/translations/rules/Bario/es.pug @@ -0,0 +1 @@ +p.boxed TODO diff --git a/client/src/translations/rules/Bario/fr.pug b/client/src/translations/rules/Bario/fr.pug new file mode 100644 index 00000000..21203baa --- /dev/null +++ b/client/src/translations/rules/Bario/fr.pug @@ -0,0 +1 @@ +p.boxed TODO diff --git a/client/src/translations/rules/Crossing/en.pug b/client/src/translations/rules/Crossing/en.pug new file mode 100644 index 00000000..aad47826 --- /dev/null +++ b/client/src/translations/rules/Crossing/en.pug @@ -0,0 +1,6 @@ +p.boxed + | Win by reaching the fifth rank with the king. + +p. + Simple variant: if the king goes beyond the horizontal line at mid-board, + it's a win. Checkmate still wins too, and all other usual rules apply. diff --git a/client/src/translations/rules/Crossing/es.pug b/client/src/translations/rules/Crossing/es.pug new file mode 100644 index 00000000..8bf89290 --- /dev/null +++ b/client/src/translations/rules/Crossing/es.pug @@ -0,0 +1,7 @@ +p.boxed + | Gana llegando a la quinta fila con el rey. + +p. + Variante simple: si el rey excede la línea horizontal al medio tablero, + está ganado. El mate siempre gana también, y + se aplican todas las demás reglas habituales. diff --git a/client/src/translations/rules/Crossing/fr.pug b/client/src/translations/rules/Crossing/fr.pug new file mode 100644 index 00000000..51969619 --- /dev/null +++ b/client/src/translations/rules/Crossing/fr.pug @@ -0,0 +1,7 @@ +p.boxed + | Gagnez en atteignant la cinquième rangée avec le roi. + +p. + Variante simple : si le roi dépasse la ligne horizontale à mi-échiquier, + c'est gagné. Le mat gagne toujours aussi, et + toutes les autres règles habituelles s'appliquent. diff --git a/client/src/translations/rules/Fugue/en.pug b/client/src/translations/rules/Fugue/en.pug new file mode 100644 index 00000000..21203baa --- /dev/null +++ b/client/src/translations/rules/Fugue/en.pug @@ -0,0 +1 @@ +p.boxed TODO diff --git a/client/src/translations/rules/Fugue/es.pug b/client/src/translations/rules/Fugue/es.pug new file mode 100644 index 00000000..21203baa --- /dev/null +++ b/client/src/translations/rules/Fugue/es.pug @@ -0,0 +1 @@ +p.boxed TODO diff --git a/client/src/translations/rules/Fugue/fr.pug b/client/src/translations/rules/Fugue/fr.pug new file mode 100644 index 00000000..21203baa --- /dev/null +++ b/client/src/translations/rules/Fugue/fr.pug @@ -0,0 +1 @@ +p.boxed TODO diff --git a/client/src/translations/rules/Hypnotic/en.pug b/client/src/translations/rules/Hypnotic/en.pug new file mode 100644 index 00000000..21203baa --- /dev/null +++ b/client/src/translations/rules/Hypnotic/en.pug @@ -0,0 +1 @@ +p.boxed TODO diff --git a/client/src/translations/rules/Hypnotic/es.pug b/client/src/translations/rules/Hypnotic/es.pug new file mode 100644 index 00000000..21203baa --- /dev/null +++ b/client/src/translations/rules/Hypnotic/es.pug @@ -0,0 +1 @@ +p.boxed TODO diff --git a/client/src/translations/rules/Hypnotic/fr.pug b/client/src/translations/rules/Hypnotic/fr.pug new file mode 100644 index 00000000..21203baa --- /dev/null +++ b/client/src/translations/rules/Hypnotic/fr.pug @@ -0,0 +1 @@ +p.boxed TODO diff --git a/client/src/translations/rules/Joker/en.pug b/client/src/translations/rules/Joker/en.pug new file mode 100644 index 00000000..21203baa --- /dev/null +++ b/client/src/translations/rules/Joker/en.pug @@ -0,0 +1 @@ +p.boxed TODO diff --git a/client/src/translations/rules/Joker/es.pug b/client/src/translations/rules/Joker/es.pug new file mode 100644 index 00000000..21203baa --- /dev/null +++ b/client/src/translations/rules/Joker/es.pug @@ -0,0 +1 @@ +p.boxed TODO diff --git a/client/src/translations/rules/Joker/fr.pug b/client/src/translations/rules/Joker/fr.pug new file mode 100644 index 00000000..21203baa --- /dev/null +++ b/client/src/translations/rules/Joker/fr.pug @@ -0,0 +1 @@ +p.boxed TODO diff --git a/client/src/translations/rules/Kingsmaker/en.pug b/client/src/translations/rules/Kingsmaker/en.pug new file mode 100644 index 00000000..df136cd6 --- /dev/null +++ b/client/src/translations/rules/Kingsmaker/en.pug @@ -0,0 +1,21 @@ +p.boxed + | Pawns can promote into an additional enemy king. + +p. + Pawns have the option to promote into an enemy king on the two last ranks, + in addition to their usual moves. + +p This allows more winning tactics: double check on two kings for example. + +figure.diagram-container + .diagram.diag12 + | fen:2kr1bnr/pbq1pppp/1pnpP3/2p5/2B3Q1/2N2N2/PPPP1PPP/R1B1K2R: + .diagram.diag22 + | fen:2kr1bnr/pbq1pkpp/1pnp4/2p5/2B3Q1/2N2N2/PPPP1PPP/R1B1K2R: + figcaption Before and after 1.exf7+. Not checkmate yet: 1...e6. Then 2.Qxe6# + +p + | This variant is based on + a(href="https://www.chessvariants.com/play/erf/Kingmake.html") + | Kingmaker Chess + |  from chessvariants.com, invented by Tony Paletta (2001). diff --git a/client/src/translations/rules/Kingsmaker/es.pug b/client/src/translations/rules/Kingsmaker/es.pug new file mode 100644 index 00000000..63422b7c --- /dev/null +++ b/client/src/translations/rules/Kingsmaker/es.pug @@ -0,0 +1,24 @@ +p.boxed + | Los peones pueden promocionarse a un rey enemigo adicional. + +p. + Los peones tienen una opción adicional: pueden ser + transformarse en un rey contrario una vez en las dos últimas filas, + además de los movimientos habituales. + +p. + Esto permite más tácticas ganadoras: + jaque doble a los dos reyes, por ejemplo. + +figure.diagram-container + .diagram.diag12 + | fen:2kr1bnr/pbq1pppp/1pnpP3/2p5/2B3Q1/2N2N2/PPPP1PPP/R1B1K2R: + .diagram.diag22 + | fen:2kr1bnr/pbq1pkpp/1pnp4/2p5/2B3Q1/2N2N2/PPPP1PPP/R1B1K2R: + figcaption Antes y después 1.exf7+. Aún no mate : 1...e6. Luego 2.Qxe6# + +p + | Esta variante se basa en + a(href="https://www.chessvariants.com/play/erf/Kingmake.html") + | Kingmaker Chess + |  de chessvariants.com, inventado por Tony Paletta (2001). diff --git a/client/src/translations/rules/Kingsmaker/fr.pug b/client/src/translations/rules/Kingsmaker/fr.pug new file mode 100644 index 00000000..fbd80e2e --- /dev/null +++ b/client/src/translations/rules/Kingsmaker/fr.pug @@ -0,0 +1,24 @@ +p.boxed + | Les pions peuvent se promouvoir en un roi ennemi supplémentaire. + +p. + Les pions disposent d'une option additionnelle : ceux-ci peuvent se + transformer en un roi adverse une fois sur les deux dernières rangées, + en plus des coups habituels. + +p. + Ceci permet plus de tactiques de gain : + échec double sur les deux rois par exemple. + +figure.diagram-container + .diagram.diag12 + | fen:2kr1bnr/pbq1pppp/1pnpP3/2p5/2B3Q1/2N2N2/PPPP1PPP/R1B1K2R: + .diagram.diag22 + | fen:2kr1bnr/pbq1pkpp/1pnp4/2p5/2B3Q1/2N2N2/PPPP1PPP/R1B1K2R: + figcaption Avant et après 1.exf7+. Pas encore mat : 1...e6. Ensuite 2.Qxe6# + +p + | Cette variante est basée sur + a(href="https://www.chessvariants.com/play/erf/Kingmake.html") + | Kingmaker Chess + |  de chessvariants.com, inventée par Tony Paletta (2001). diff --git a/client/src/translations/rules/Mesmer/en.pug b/client/src/translations/rules/Mesmer/en.pug new file mode 100644 index 00000000..21203baa --- /dev/null +++ b/client/src/translations/rules/Mesmer/en.pug @@ -0,0 +1 @@ +p.boxed TODO diff --git a/client/src/translations/rules/Mesmer/es.pug b/client/src/translations/rules/Mesmer/es.pug new file mode 100644 index 00000000..21203baa --- /dev/null +++ b/client/src/translations/rules/Mesmer/es.pug @@ -0,0 +1 @@ +p.boxed TODO diff --git a/client/src/translations/rules/Mesmer/fr.pug b/client/src/translations/rules/Mesmer/fr.pug new file mode 100644 index 00000000..21203baa --- /dev/null +++ b/client/src/translations/rules/Mesmer/fr.pug @@ -0,0 +1 @@ +p.boxed TODO diff --git a/client/src/translations/rules/Rollerball/en.pug b/client/src/translations/rules/Rollerball/en.pug new file mode 100644 index 00000000..21203baa --- /dev/null +++ b/client/src/translations/rules/Rollerball/en.pug @@ -0,0 +1 @@ +p.boxed TODO diff --git a/client/src/translations/rules/Rollerball/es.pug b/client/src/translations/rules/Rollerball/es.pug new file mode 100644 index 00000000..21203baa --- /dev/null +++ b/client/src/translations/rules/Rollerball/es.pug @@ -0,0 +1 @@ +p.boxed TODO diff --git a/client/src/translations/rules/Rollerball/fr.pug b/client/src/translations/rules/Rollerball/fr.pug new file mode 100644 index 00000000..21203baa --- /dev/null +++ b/client/src/translations/rules/Rollerball/fr.pug @@ -0,0 +1 @@ +p.boxed TODO diff --git a/client/src/translations/rules/Shogun/en.pug b/client/src/translations/rules/Shogun/en.pug new file mode 100644 index 00000000..21203baa --- /dev/null +++ b/client/src/translations/rules/Shogun/en.pug @@ -0,0 +1 @@ +p.boxed TODO diff --git a/client/src/translations/rules/Shogun/es.pug b/client/src/translations/rules/Shogun/es.pug new file mode 100644 index 00000000..21203baa --- /dev/null +++ b/client/src/translations/rules/Shogun/es.pug @@ -0,0 +1 @@ +p.boxed TODO diff --git a/client/src/translations/rules/Shogun/fr.pug b/client/src/translations/rules/Shogun/fr.pug new file mode 100644 index 00000000..21203baa --- /dev/null +++ b/client/src/translations/rules/Shogun/fr.pug @@ -0,0 +1 @@ +p.boxed TODO diff --git a/client/src/translations/rules/Spartan/en.pug b/client/src/translations/rules/Spartan/en.pug new file mode 100644 index 00000000..21203baa --- /dev/null +++ b/client/src/translations/rules/Spartan/en.pug @@ -0,0 +1 @@ +p.boxed TODO diff --git a/client/src/translations/rules/Spartan/es.pug b/client/src/translations/rules/Spartan/es.pug new file mode 100644 index 00000000..21203baa --- /dev/null +++ b/client/src/translations/rules/Spartan/es.pug @@ -0,0 +1 @@ +p.boxed TODO diff --git a/client/src/translations/rules/Spartan/fr.pug b/client/src/translations/rules/Spartan/fr.pug new file mode 100644 index 00000000..21203baa --- /dev/null +++ b/client/src/translations/rules/Spartan/fr.pug @@ -0,0 +1 @@ +p.boxed TODO diff --git a/client/src/translations/rules/Squatter/en.pug b/client/src/translations/rules/Squatter/en.pug new file mode 100644 index 00000000..79e66387 --- /dev/null +++ b/client/src/translations/rules/Squatter/en.pug @@ -0,0 +1,7 @@ +p.boxed + | Win by being safe on last rank. + +p. + Simple variant: if you can move a piece safely on the last rank, it's a win. + If the opponent can capture it, you don't win. + Checkmate still wins too, and all other usual rules apply. diff --git a/client/src/translations/rules/Squatter/es.pug b/client/src/translations/rules/Squatter/es.pug new file mode 100644 index 00000000..f2c53040 --- /dev/null +++ b/client/src/translations/rules/Squatter/es.pug @@ -0,0 +1,7 @@ +p.boxed + | Gana llegando a salvo en la última fila. + +p. + Variante simple: si puede mover una pieza de forma segura a la última fila, + está ganado. Si el adversario puede capturarla, tu no ganas. + El mate siempre gana también y se aplican todas las demás reglas habituales. diff --git a/client/src/translations/rules/Squatter/fr.pug b/client/src/translations/rules/Squatter/fr.pug new file mode 100644 index 00000000..913d02c8 --- /dev/null +++ b/client/src/translations/rules/Squatter/fr.pug @@ -0,0 +1,8 @@ +p.boxed + | Gagnez en étant en sécurité sur la dernière rangée. + +p. + Variante simple : si vous pouvez déplacer une pièce de façon sécurisée sur + la dernière rangée, c'est gagné. Si l'adversaire peut la capturer, + vous ne gagnez pas. Le mat gagne toujours aussi, + et toutes les autres règles habituelles s'appliquent. diff --git a/client/src/translations/variants/en.pug b/client/src/translations/variants/en.pug index 53f210e7..312df305 100644 --- a/client/src/translations/variants/en.pug +++ b/client/src/translations/variants/en.pug @@ -391,12 +391,14 @@ p. one of their kind on this website. - var varlist = [ + "Alapo", "Alice", "Ambiguous", "Avalanche", "Bicolour", "Brotherhood", "Castle", + "Crossing", "Doublearmy", "Evolution", "Forward", @@ -404,6 +406,7 @@ p. "Gridolina", "Hamilton", "Isardam", + "Kingsmaker", "Magnetic", "Maharajah", "Otage", @@ -411,6 +414,7 @@ p. "Parachute", "Relayup", "Screen", + "Squatter", "Takenmake", "Titan", "Wormhole" diff --git a/client/src/translations/variants/es.pug b/client/src/translations/variants/es.pug index c1123f7a..9d360c8e 100644 --- a/client/src/translations/variants/es.pug +++ b/client/src/translations/variants/es.pug @@ -402,12 +402,14 @@ p. el único representante de su tipo en este sitio. - var varlist = [ + "Alapo", "Alice", "Ambiguous", "Avalanche", "Bicolour", "Brotherhood", "Castle", + "Crossing", "Doublearmy", "Evolution", "Forward", @@ -415,6 +417,7 @@ p. "Gridolina", "Hamilton", "Isardam", + "Kingsmaker", "Magnetic", "Maharajah", "Otage", @@ -422,6 +425,7 @@ p. "Parachute", "Relayup", "Screen", + "Squatter", "Takenmake", "Titan", "Wormhole" diff --git a/client/src/translations/variants/fr.pug b/client/src/translations/variants/fr.pug index c0b0ee7c..411a2056 100644 --- a/client/src/translations/variants/fr.pug +++ b/client/src/translations/variants/fr.pug @@ -401,12 +401,14 @@ p. l'unique représentant de leur type sur ce site. - var varlist = [ + "Alapo", "Alice", "Ambiguous", "Avalanche", "Bicolour", "Brotherhood", "Castle", + "Crossing", "Doublearmy", "Evolution", "Forward", @@ -414,6 +416,7 @@ p. "Gridolina", "Hamilton", "Isardam", + "Kingsmaker", "Magnetic", "Maharajah", "Otage", @@ -421,6 +424,7 @@ p. "Parachute", "Relayup", "Screen", + "Squatter", "Takenmake", "Titan", "Wormhole" diff --git a/client/src/variants/Alapo.js b/client/src/variants/Alapo.js new file mode 100644 index 00000000..6864457e --- /dev/null +++ b/client/src/variants/Alapo.js @@ -0,0 +1,224 @@ +import { ChessRules } from "@/base_rules"; + +export class AlapoRules extends ChessRules { + + static get HasFlags() { + return false; + } + + static get HasEnpassant() { + return false; + } + + static get Lines() { + return [ + [[1, 0], [1, 6]], + [[5, 0], [5, 6]] + ]; + } + + static get PIECES() { + return [V.ROOK, V.BISHOP, V.QUEEN, V.ROOK_S, V.BISHOP_S, V.QUEEN_S]; + } + + static get ROOK_S() { + return "t"; + } + static get BISHOP_S() { + return "c"; + } + static get QUEEN_S() { + return "s"; + } + + getPotentialMinirookMoves(sq) { + return super.getSlideNJumpMoves(sq, V.steps[V.ROOK], "oneStep"); + } + getPotentialMinibishopMoves(sq) { + return super.getSlideNJumpMoves(sq, V.steps[V.BISHOP], "oneStep"); + } + getPotentialMiniqueenMoves(sq) { + return ( + super.getSlideNJumpMoves( + sq, V.steps[V.ROOK].concat(V.steps[V.BISHOP]), "oneStep") + ); + } + + getPotentialMovesFrom(sq) { + switch (this.getPiece(sq[0], sq[1])) { + case V.ROOK: return super.getPotentialRookMoves(sq); + case V.BISHOP: return super.getPotentialBishopMoves(sq); + case V.QUEEN: return super.getPotentialQueenMoves(sq); + case V.ROOK_S: return this.getPotentialMinirookMoves(sq); + case V.BISHOP_S: return this.getPotentialMinibishopMoves(sq); + case V.QUEEN_S: return this.getPotentialMiniqueenMoves(sq); + } + return []; + } + + static get size() { + return { x: 6, y: 6 }; + } + + getPpath(b, color, score, orientation) { + // 'i' for "inversed": + const suffix = (b[0] == orientation ? "" : "i"); + return "Alapo/" + b + suffix; + } + + static GenRandInitFen(randomness) { + if (randomness == 0) + return "rbqqbr/tcssct/6/6/TCSSCT/RBQQBR w 0"; + + const piece2pawn = { + r: 't', + q: 's', + b: 'c' + }; + + let pieces = { w: new Array(6), b: new Array(6) }; + // 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']; + break; + } + + let positions = ArrayFun.range(6); + + // Get random squares for bishops + let randIndex = 2 * randInt(3); + const bishop1Pos = positions[randIndex]; + let randIndex_tmp = 2 * randInt(3) + 1; + const bishop2Pos = positions[randIndex_tmp]; + positions.splice(Math.max(randIndex, randIndex_tmp), 1); + positions.splice(Math.min(randIndex, randIndex_tmp), 1); + + // Get random square for queens + randIndex = randInt(4); + const queen1Pos = positions[randIndex]; + positions.splice(randIndex, 1); + randIndex = randInt(3); + const queen2Pos = positions[randIndex]; + positions.splice(randIndex, 1); + + // Rooks positions are now fixed, + const rook1Pos = positions[0]; + const rook2Pos = positions[1]; + + pieces[c][rook1Pos] = "r"; + pieces[c][bishop1Pos] = "b"; + pieces[c][queen1Pos] = "q"; + pieces[c][queen2Pos] = "q"; + pieces[c][bishop2Pos] = "b"; + pieces[c][rook2Pos] = "r"; + } + return ( + pieces["b"].join("") + "/" + + pieces["b"].map(p => piece2pawn[p]).join() + + "/8/8/8/8/" + + pieces["w"].map(p => piece2pawn[p].toUpperCase()).join() + "/" + + pieces["w"].join("").toUpperCase() + + " w 0" + ); + } + + static IsGoodPosition(position) { + if (position.length == 0) return false; + const rows = position.split("/"); + if (rows.length != V.size.x) return false; + // Just check that at least one piece of each color is there: + let pieces = { "w": 0, "b": 0 }; + for (let row of rows) { + let sumElts = 0; + for (let i = 0; i < row.length; i++) { + const lowerRi = row[i].toLowerCase(); + if (V.PIECES.includes(lowerRi)) { + pieces[row[i] == lowerRi ? "b" : "w"]++; + sumElts++; + } + else { + const num = parseInt(row[i], 10); + if (isNaN(num)) return false; + sumElts += num; + } + } + if (sumElts != V.size.y) return false; + } + if (Object.values(pieces).some(v => v == 0)) return false; + return true; + } + + // Find possible captures by opponent on [x, y] + findCaptures([x, y]) { + const color = this.getColor(x, y); + let moves = []; + const steps = V.steps[V.ROOK].concat(V.steps[V.BISHOP]); + const oppCol = V.GetOppCol(color); + for (let loop = 0; loop < steps.length; loop++) { + const step = steps[loop]; + let i = x + step[0]; + let j = y + step[1]; + let stepsAfter = 1; + while (V.OnBoard(i, j) && this.board[i][j] == V.EMPTY) { + i += step[0]; + j += step[1]; + stepsAfter++; + } + if ( + V.OnBoard(i, j) && + this.board[i][j] != V.EMPTY && + this.getColor(i, j) == oppCol + ) { + const oppPiece = this.getPiece(i, j); + if ( + ( + stepsAfter >= 2 && + [V.ROOK_S, V.BISHOP_S, V.QUEEN_S].includes(oppPiece) + ) + || + ( + [V.BISHOP, V.BISHOP_S].includes(oppPiece) && + step.some(e => e == 0) + ) + || + ( + [V.ROOK, V.ROOK_S].includes(oppPiece) && + step.every(e => e != 0) + ) + ) { + continue; + } + return true; + } + } + return false; + } + + postPlay() {} + postUndo() {} + + getCheckSquares() { + return []; + } + filterValid(moves) { + return moves; + } + + getCurrentScore() { + // Try both colors (to detect potential suicides) + for (let c of ['w', 'b']) { + const oppCol = V.GetOppCol(c); + const goal = (c == 'w' ? 0 : 5); + if ( + this.board[goal].some( + (b,j) => b[0] == c && !this.findCaptures([goal, j]) + ) + ) { + return c == 'w' ? "1-0" : "0-1"; + } + } + return super.getCurrentScore(); + } + +}; diff --git a/client/src/variants/Crossing.js b/client/src/variants/Crossing.js new file mode 100644 index 00000000..40907461 --- /dev/null +++ b/client/src/variants/Crossing.js @@ -0,0 +1,30 @@ +import { ChessRules } from "@/base_rules"; + +export class CrossingRules extends ChessRules { + + static get Lines() { + return [ [[4, 0], [4, 8]] ]; + } + + getCurrentScore() { + // Turn has changed: + const color = V.GetOppCol(this.turn); + const secondHalf = (color == 'w' ? [0, 1, 2, 3] : [4, 5, 6, 7]); + if (secondHalf.includes(this.kingPos[color][0])) + // Half-board is crossed + return color == "w" ? "1-0" : "0-1"; + return super.getCurrentScore(); + } + + evalPosition() { + // Count material: + let evaluation = super.evalPosition(); + // Ponder with king position: + return ( + evaluation/5 + + Math.abs(this.kingPos["w"][0] - 3.5) - + Math.abs(this.kingPos["b"][0] - 3.5) + ); + } + +}; diff --git a/client/src/variants/Football.js b/client/src/variants/Football.js index bde38e53..430e31ac 100644 --- a/client/src/variants/Football.js +++ b/client/src/variants/Football.js @@ -1,6 +1,5 @@ import { ChessRules } from "@/base_rules"; -import { ArrayFun } from "@/utils/array"; -import { shuffle } from "@/utils/alea"; +import { SuicideRules } from "@/variants/Suicide"; export class FootballRules extends ChessRules { @@ -44,7 +43,8 @@ export class FootballRules extends ChessRules { if (V.PIECES.includes(lowerRi)) { pieces[row[i] == lowerRi ? "b" : "w"]++; sumElts++; - } else { + } + else { const num = parseInt(row[i], 10); if (isNaN(num)) return false; sumElts += num; @@ -82,36 +82,7 @@ export class FootballRules extends ChessRules { } static GenRandInitFen(randomness) { - if (randomness == 0) - return "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w 0 -"; - - let pieces = { w: new Array(8), b: new Array(8) }; - for (let c of ["w", "b"]) { - if (c == 'b' && randomness == 1) { - pieces['b'] = pieces['w']; - break; - } - - // Get random squares for every piece, totally freely - let positions = shuffle(ArrayFun.range(8)); - const composition = ['b', 'b', 'r', 'r', 'n', 'n', 'k', 'q']; - const rem2 = positions[0] % 2; - if (rem2 == positions[1] % 2) { - // Fix bishops (on different colors) - for (let i=2; i<8; i++) { - if (positions[i] % 2 != rem2) - [positions[1], positions[i]] = [positions[i], positions[1]]; - } - } - for (let i = 0; i < 8; i++) pieces[c][positions[i]] = composition[i]; - } - return ( - pieces["b"].join("") + - "/pppppppp/8/8/8/8/PPPPPPPP/" + - pieces["w"].join("").toUpperCase() + - // En-passant allowed, but no flags - " w 0 -" - ); + return SuicideRules.GenRandInitFen(randomness); } }; diff --git a/client/src/variants/Kingsmaker.js b/client/src/variants/Kingsmaker.js new file mode 100644 index 00000000..a5d21047 --- /dev/null +++ b/client/src/variants/Kingsmaker.js @@ -0,0 +1,114 @@ +import { ChessRules } from "@/base_rules"; + +export class KingsmakerRules extends ChessRules { + + static IsGoodPosition(position) { + if (position.length == 0) return false; + const rows = position.split("/"); + if (rows.length != V.size.x) return false; + let kings = { "k": 0, "K": 0 }; + for (let row of rows) { + let sumElts = 0; + for (let i = 0; i < row.length; i++) { + if (['K','k'].includes(row[i])) kings[row[i]]++; + if (V.PIECES.includes(row[i].toLowerCase())) sumElts++; + else { + const num = parseInt(row[i], 10); + if (isNaN(num) || num <= 0) return false; + sumElts += num; + } + } + if (sumElts != V.size.y) return false; + } + // At least one king per color. + if (Object.values(kings).some(v => v == 0)) return false; + return true; + } + + scanKings() {} + + getPotentialMovesFrom([x, y]) { + const moves = super.getPotentialMovesFrom([x, y]); + if (this.getPiece(x, y) != V.PAWN) return moves; + const c = this.getColor(x, y); + const oppCol = V.GetOppCol(c); + const forward = (c == 'w' ? -1 : 1); + const lastRanks = (c == 'w' ? [0, 1] : [7, 6]); + let newKingMoves = []; + if (lastRanks.includes(x + forward)) { + // Manually add promotion into enemy king: + const trials = [ + { step: [forward, 0] }, + { step: [forward, 1], capture: true }, + { step: [forward, -1], capture: true } + ]; + for (let s of trials) { + const [i, j] = [x + s.step[0], y + s.step[1]]; + if ( + V.OnBoard(i, j) && + ( + (!s.capture && this.board[i][j] == V.EMPTY) || + ( + s.capture && + this.board[i][j] != V.EMPTY && + this.getColor(i, j) == oppCol + ) + ) + ) { + newKingMoves.push( + super.getBasicMove([x, y], [i, j], { c: oppCol, p: V.KING }) + ); + } + } + } + return moves.concat(newKingMoves); + } + + underCheck(color) { + // First at first check found (if any) + const oppCol = V.GetOppCol(color); + for (let i=0; i<8; i++) { + for (let j=0; j<8; j++) { + if ( + this.board[i][j] != V.EMPTY && + this.getPiece(i, j) == V.KING && + this.getColor(i, j) == color + ) { + if (super.isAttacked([i, j], oppCol)) return true; + } + } + } + return false; + } + + getCheckSquares() { + const color = this.turn; + const oppCol = V.GetOppCol(color); + let res = []; + // Scan all kings + for (let i=0; i<8; i++) { + for (let j=0; j<8; j++) { + if ( + this.board[i][j] != V.EMPTY && + this.getPiece(i, j) == V.KING && + this.getColor(i, j) == color + ) { + if (super.isAttacked([i, j], oppCol)) res.push([i, j]); + } + } + } + return res; + } + + postPlay(move) { + this.updateCastleFlags(move, move.vanish[0].p); + } + + postUndo() {} + + static get VALUES() { + // Assign -5 to the king, so that the bot sometimes promote into king + return Object.assign({}, ChessRules.VALUES, { k: -5 }); + } + +}; diff --git a/client/src/variants/Squatter.js b/client/src/variants/Squatter.js new file mode 100644 index 00000000..f9976790 --- /dev/null +++ b/client/src/variants/Squatter.js @@ -0,0 +1,98 @@ +import { ChessRules } from "@/base_rules"; + +export class SquatterRules extends ChessRules { + + static get Lines() { + return [ + [[1, 0], [1, 8]], + [[7, 0], [7, 8]] + ]; + } + + // Find possible captures by opponent on [x, y] + findCaptures([x, y]) { + const color = this.getColor(x, y); + const forward = (color == 'w' ? -1 : 1); + let moves = []; + const steps = { + // Rook and bishop: included in queen case + p: { s: [[forward, -1], [forward, 1]], one: true }, + n: { s: V.steps[V.KNIGHT], one: true }, + q: { s: V.steps[V.ROOK].concat(V.steps[V.BISHOP]) }, + k: { s: V.steps[V.ROOK].concat(V.steps[V.BISHOP]), one: true } + }; + const oppCol = V.GetOppCol(color); + Object.keys(steps).forEach(piece => { + outerLoop: for (let loop = 0; loop < steps[piece].s.length; loop++) { + const step = steps[piece].s[loop]; + let i = x + step[0]; + let j = y + step[1]; + while (V.OnBoard(i, j) && this.board[i][j] == V.EMPTY) { + if (steps[piece].one) continue outerLoop; + i += step[0]; + j += step[1]; + } + if ( + V.OnBoard(i, j) && + this.board[i][j] != V.EMPTY && + this.getColor(i, j) == oppCol + ) { + const oppPiece = this.getPiece(i, j); + if ( + oppPiece == piece || + ( + piece == V.QUEEN && + ( + (oppPiece == V.ROOK && step.some(e => e == 0)) || + (oppPiece == V.BISHOP && step.every(e => e != 0)) + ) + ) + ) + // Possible capture (do not care about promotions): + moves.push(this.getBasicMove([i, j], [x, y])); + } + } + }); + return moves; + } + + someValid(moves, color) { + // Stop at first valid move found: + for (let m of moves) { + this.play(m); + const res = !this.underCheck(color); + this.undo(m); + if (res) return true; + } + return false; + } + + getCurrentScore() { + // Try both colors (to detect potential suicides) + for (let c of ['w', 'b']) { + const oppCol = V.GetOppCol(c); + const goal = (c == 'w' ? 0 : 7); + if ( + this.board[goal].some( + (b,j) => { + return ( + b[0] == c && + ( + !this.isAttacked([goal, j], oppCol) || + !this.someValid(this.findCaptures([goal, j]), oppCol) + ) + ); + } + ) + ) { + return c == 'w' ? "1-0" : "0-1"; + } + } + return super.getCurrentScore(); + } + + static get SEARCH_DEPTH() { + return 2; + } + +}; diff --git a/client/src/variants/Suicide.js b/client/src/variants/Suicide.js index 05fb19c3..e71e3a2e 100644 --- a/client/src/variants/Suicide.js +++ b/client/src/variants/Suicide.js @@ -29,7 +29,8 @@ export class SuicideRules extends ChessRules { if (V.PIECES.includes(lowerRi)) { pieces[row[i] == lowerRi ? "b" : "w"]++; sumElts++; - } else { + } + else { const num = parseInt(row[i], 10); if (isNaN(num)) return false; sumElts += num; diff --git a/client/src/variants/Zen.js b/client/src/variants/Zen.js index eb6748d0..7edbe40a 100644 --- a/client/src/variants/Zen.js +++ b/client/src/variants/Zen.js @@ -79,6 +79,7 @@ export class ZenRules extends ChessRules { } if ( V.OnBoard(i, j) && + this.board[i][j] != V.EMPTY && this.getColor(i, j) == oppCol && this.getPiece(i, j) == asA ) { @@ -88,7 +89,8 @@ export class ZenRules extends ChessRules { promotionPieces.forEach(p => { moves.push(this.getBasicMove([x, y], [i, j], { c: color, p: p })); }); - } else { + } + else { // All other cases moves.push(this.getBasicMove([x, y], [i, j])); } diff --git a/server/db/populate.sql b/server/db/populate.sql index fc814642..3c703532 100644 --- a/server/db/populate.sql +++ b/server/db/populate.sql @@ -12,6 +12,7 @@ insert or ignore into Variants (name, description, noProblems) values insert or ignore into Variants (name, description) values ('Absorption', 'Absorb powers'), + ('Alapo', 'Geometric Chess'), ('Alice', 'Both sides of the mirror'), ('Allmate1', 'Mate any piece (v1)'), ('Allmate2', 'Mate any piece (v2)'), @@ -44,6 +45,7 @@ insert or ignore into Variants (name, description) values ('Coregal', 'Two royal pieces'), ('Coronation', 'Long live the Queen'), ('Crazyhouse', 'Captures reborn'), + ('Crossing', 'Cross the river'), ('Cylinder', 'Neverending rows'), ('Diamond', 'Rotating board'), ('Discoduel', 'Enter the disco'), @@ -71,6 +73,7 @@ insert or ignore into Variants (name, description) values ('Isardam', 'No paralyzed pieces'), ('Janggi', 'Korean Chess'), ('Kinglet', 'Protect your pawns'), + ('Kingsmaker', 'Promote into kings'), ('Knightmate', 'Mate the knight'), ('Knightpawns', 'Knight versus pawns'), ('Knightrelay1', 'Move like a knight (v1)'), @@ -120,6 +123,7 @@ insert or ignore into Variants (name, description) values ('Shatranj', 'Ancient rules'), ('Shogi', 'Japanese Chess'), ('Sittuyin', 'Burmese Chess'), + ('Squatter', 'Squat last rank'), ('Suicide', 'Lose all pieces'), ('Suction', 'Attract opposite king'), ('Swap', 'Dangerous captures'),