*.ico filter=fat
*.pdf filter=fat
*.png filter=fat
+*.jpg filter=fat
*.gif filter=fat
*.flac filter=fat
--- /dev/null
+*
+!generateSVG.py
+!.gitignore
--- /dev/null
+#!/usr/bin/env python
+
+# Compose each piece SVG with numbers
+# https://travishorn.com/removing-parts-of-shapes-in-svg-b539a89e5649
+# https://developer.mozilla.org/fr/docs/Web/SVG/Tutoriel/Paths
+
+preamble = """<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
+<svg xmlns="http://www.w3.org/2000/svg" version="1.0" width="230" height="230">"""
+
+black = '<circle cx="115" cy="115" r="100" fill="red" stroke="darkslategray"/>'
+white = '<circle cx="115" cy="115" r="100" fill="yellow" stroke="darkslategray"/>'
+
+digits = [
+ # 1
+ '<path d="M125,95 v40"',
+ # 2
+ '<path d="M105,95 h20 v20 h-20 v20 h20"',
+ # 3
+ '<path d="M105,95 h20 v20 h-20 M125,115 v20 h-20"',
+ # 4
+ '<path d="M105,95 v20 h20 v20 M125,95 v20"',
+ # 5
+ '<path d="M125,95 h-20 v20 h20 v20 h-20"'
+]
+
+final = "</svg>"
+
+for color in ["white", "black"]:
+ for number in range(5):
+ filename = ('w' if color == "white" else 'b') + chr(97 + number + 1) + ".svg"
+ f = open(filename, "w")
+ f.write(preamble)
+ f.write("\n")
+ f.write(white if color == "white" else black)
+ f.write("\n")
+ f.write(digits[number] + ' fill="none" stroke-width="4" ' + ('stroke="red"' if color == "white" else 'stroke="yellow"') + '/>')
+ f.write("\n")
+ f.write(final)
+ f.close()
digits = {
"left": [
# 1
- '<path d="M90,95 v40" stroke="red" fill="none" stroke-width="2"/>',
+ '<path d="M90,95 v40"',
# 2
- '<path d="M70,95 h20 v20 h-20 v20 h20" stroke="red" fill="none" stroke-width="2"/>',
+ '<path d="M70,95 h20 v20 h-20 v20 h20"',
# 3
- '<path d="M70,95 h20 v20 h-20 M90,115 v20 h-20" stroke="red" fill="none" stroke-width="2"/>',
+ '<path d="M70,95 h20 v20 h-20 M90,115 v20 h-20"',
# 4
- '<path d="M70,95 v20 h20 v20 M90,95 v20" stroke="red" fill="none" stroke-width="2"/>',
+ '<path d="M70,95 v20 h20 v20 M90,95 v20"',
# 5
- '<path d="M90,95 h-20 v20 h20 v20 h-20" stroke="red" fill="none" stroke-width="2"/>',
+ '<path d="M90,95 h-20 v20 h20 v20 h-20"',
# 6
- '<path d="M90,95 h-20 v40 h20 v-20 h-20" stroke="red" fill="none" stroke-width="2"/>',
+ '<path d="M90,95 h-20 v40 h20 v-20 h-20"',
# 7
- '<path d="M70,95 h20 v40" stroke="red" fill="none" stroke-width="2"/>',
+ '<path d="M70,95 h20 v40"',
# 8
- '<path d="M70,95 h20 v40 h-20 z M70,115 h20" stroke="red" fill="none" stroke-width="2"/>',
+ '<path d="M70,95 h20 v40 h-20 z M70,115 h20"',
# 9
- '<path d="M70,135 h20 v-40 h-20 v20 h20" stroke="red" fill="none" stroke-width="2"/>',
+ '<path d="M70,135 h20 v-40 h-20 v20 h20"',
# 10
- '<path d="M60,95 v40 M70,95 h20 v40 h-20 v-40" stroke="red" fill="none" stroke-width="2"/>',
+ '<path d="M60,95 v40 M70,95 h20 v40 h-20 v-40"',
# 11
- '<path d="M60,95 v40 M90,95 v40" stroke="red" fill="none" stroke-width="2"/>',
+ '<path d="M60,95 v40 M90,95 v40"',
# 12
- '<path d="M60,95 v40 M70,95 h20 v20 h-20 M90,115 v20 h-20" stroke="red" fill="none" stroke-width="2"/>'
+ '<path d="M60,95 v40 M70,95 h20 v20 h-20 M90,115 v20 h-20"'
],
"right": [
# 1
- '<path d="M180,95 v40" stroke="red" fill="none" stroke-width="2"/>',
+ '<path d="M180,95 v40"',
# 2
- '<path d="M160,95 h20 v20 h-20 v20 h20" stroke="red" fill="none" stroke-width="2"/>',
+ '<path d="M160,95 h20 v20 h-20 v20 h20"',
# 3
- '<path d="M160,95 h20 v20 h-20 M180,115 v20 h-20" stroke="red" fill="none" stroke-width="2"/>',
+ '<path d="M160,95 h20 v20 h-20 M180,115 v20 h-20"',
# 4
- '<path d="M160,95 v20 h20 v20 M180,95 v20" stroke="red" fill="none" stroke-width="2"/>',
+ '<path d="M160,95 v20 h20 v20 M180,95 v20"',
# 5
- '<path d="M180,95 h-20 v20 h20 v20 h-20" stroke="red" fill="none" stroke-width="2"/>',
+ '<path d="M180,95 h-20 v20 h20 v20 h-20"',
# 6
- '<path d="M180,95 h-20 v40 h20 v-20 h-20" stroke="red" fill="none" stroke-width="2"/>',
+ '<path d="M180,95 h-20 v40 h20 v-20 h-20"',
# 7
- '<path d="M160,95 h20 v40" stroke="red" fill="none" stroke-width="2"/>',
+ '<path d="M160,95 h20 v40"',
# 8
- '<path d="M160,95 h20 v40 h-20 z M160,115 h20" stroke="red" fill="none" stroke-width="2"/>',
+ '<path d="M160,95 h20 v40 h-20 z M160,115 h20"',
# 9
- '<path d="M160,135 h20 v-40 h-20 v20 h20" stroke="red" fill="none" stroke-width="2"/>',
+ '<path d="M160,135 h20 v-40 h-20 v20 h20"',
# 10
- '<path d="M150,95 v40 M160,95 h20 v40 h-20 v-40" stroke="red" fill="none" stroke-width="2"/>',
+ '<path d="M150,95 v40 M160,95 h20 v40 h-20 v-40"',
# 11
- '<path d="M150,95 v40 M180,95 v40" stroke="red" fill="none" stroke-width="2"/>',
+ '<path d="M150,95 v40 M180,95 v40"',
# 12
- '<path d="M150,95 v40 M160,95 h20 v20 h-20 M180,115 v20 h-20" stroke="red" fill="none" stroke-width="2"/>'
+ '<path d="M150,95 v40 M160,95 h20 v20 h-20 M180,115 v20 h-20"'
]
}
filename = chr(65 + left + chrShift) + chr(65 + right + chrShift) + ".svg"
f = open(filename, "w")
f.write(preamble)
- f.write("\n");
+ f.write("\n")
f.write(black_right if colorLeft == "white" else white_right)
- f.write("\n");
+ f.write("\n")
f.write(white_left if colorLeft == "white" else black_left)
- f.write("\n");
- f.write(digits["left"][left])
- f.write("\n");
- f.write(digits["right"][right])
- f.write("\n");
+ f.write("\n")
+ f.write(digits["left"][left] + ' fill="none" stroke-width="4" ' + ('stroke="red"' if colorLeft == "white" else 'stroke="orange"') + '/>')
+ f.write("\n")
+ f.write(digits["right"][right] + ' fill="none" stroke-width="4" ' + ('stroke="red"' if colorLeft == "black" else 'stroke="orange"') + '/>')
+ f.write("\n")
f.write(final)
f.close()
digits = [
# 1
- '<path d="M125,95 v40" stroke="red" fill="none" stroke-width="2"/>',
+ '<path d="M125,95 v40"',
# 2
- '<path d="M105,95 h20 v20 h-20 v20 h20" stroke="red" fill="none" stroke-width="2"/>',
+ '<path d="M105,95 h20 v20 h-20 v20 h20"',
# 3
- '<path d="M105,95 h20 v20 h-20 M125,115 v20 h-20" stroke="red" fill="none" stroke-width="2"/>',
+ '<path d="M105,95 h20 v20 h-20 M125,115 v20 h-20"',
# 4
- '<path d="M105,95 v20 h20 v20 M125,95 v20" stroke="red" fill="none" stroke-width="2"/>',
+ '<path d="M105,95 v20 h20 v20 M125,95 v20"',
# 5
- '<path d="M125,95 h-20 v20 h20 v20 h-20" stroke="red" fill="none" stroke-width="2"/>',
+ '<path d="M125,95 h-20 v20 h20 v20 h-20"',
# 6
- '<path d="M125,95 h-20 v40 h20 v-20 h-20" stroke="red" fill="none" stroke-width="2"/>',
+ '<path d="M125,95 h-20 v40 h20 v-20 h-20"',
# 7
- '<path d="M105,95 h20 v40" stroke="red" fill="none" stroke-width="2"/>',
+ '<path d="M105,95 h20 v40"',
# 8
- '<path d="M105,95 h20 v40 h-20 z M105,115 h20" stroke="red" fill="none" stroke-width="2"/>',
+ '<path d="M105,95 h20 v40 h-20 z M105,115 h20"',
# 9
- '<path d="M105,135 h20 v-40 h-20 v20 h20" stroke="red" fill="none" stroke-width="2"/>',
+ '<path d="M105,135 h20 v-40 h-20 v20 h20"',
# 10
- '<path d="M100,95 v40 M110,95 h20 v40 h-20 v-40" stroke="red" fill="none" stroke-width="2"/>',
+ '<path d="M100,95 v40 M110,95 h20 v40 h-20 v-40"',
# 11
- '<path d="M100,95 v40 M130,95 v40" stroke="red" fill="none" stroke-width="2"/>',
+ '<path d="M100,95 v40 M130,95 v40"',
# 12
- '<path d="M100,95 v40 M110,95 h20 v20 h-20 M130,115 v20 h-20" stroke="red" fill="none" stroke-width="2"/>'
+ '<path d="M100,95 v40 M110,95 h20 v20 h-20 M130,115 v20 h-20"'
]
final = "</svg>"
filename = chr(65 + number + chrShift) + "@.svg"
f = open(filename, "w")
f.write(preamble)
- f.write("\n");
+ f.write("\n")
f.write(white if color == "white" else black)
- f.write("\n");
- f.write(digits[number])
- f.write("\n");
+ f.write("\n")
+ f.write(digits[number] + ' fill="none" stroke-width="4" ' + ('stroke="red"' if color == "white" else 'stroke="orange"') + '/>')
+ f.write("\n")
f.write(final)
f.close()
--- /dev/null
+#$# git-fat 761b5f04a60c2c2438cf2777453ba42aceb16da3 80995
p.boxed
- | TODO
+ | Stack towers freely, so that your color appears on top.
+
+p.
+ There are initially 48 pieces placed on a 49 squares irregular board.
+ "White" takes yellow pieces, and "black" gets the red ones.
+
+figure.diagram-container
+ .diagram
+ | fen:xxBbxxxxx/xBbBbxxxx/xbBbBbBxx/xBbBbBbBb/BbBb1bBbB/bBbBbBbBx/xxBbBbBbx/xxxxbBbBx/xxxxxbBxx:
+ figcaption Deterministic initial position.
+
+p.
+ At each turn, take any tower of less than 5 pieces (the number
+ printed on it) and put it on an adjacent tower, such that
+ the resulting construction isn't more than 5 units tall.
+
+p.
+ When no moves are possible anymore, the game is over.
+ The winner is the player having the largest number of towers
+ of his color (on top)
+
+h3 More information
+
+p
+ | Few online resources about this game. The rules are explained
+ | for example on
+ a(href="http://jeuxstrategie.free.fr/Avalam_complet.php") this page
+ | . See also the Avalam page on
+ a(href="https://www.jeuxdenim.be/jeu-Avalam") jeuxdenim.be
+ | .
+
+p Inventor: Philippe Deweys (1995)
p.boxed
- | TODO
+ | Apila libremente las torres, para que tu color
+ | aparece en la parte superior.
+
+p.
+ Inicialmente se distribuyen 48 piezas en un tablero irregular de 49 casillas.
+ Las "blancas" toman las piezas amarillas,
+ y las "negras" juegan con las rojas.
+
+figure.diagram-container
+ .diagram
+ | fen:xxBbxxxxx/xBbBbxxxx/xbBbBbBxx/xBbBbBbBb/BbBb1bBbB/bBbBbBbBx/xxBbBbBbx/xxxxbBbBx/xxxxxbBxx:
+ figcaption Posición inicial determinista.
+
+p.
+ En cada turno, tome cualquier torre con menos de 5 piezas (el número
+ indicado arriba) y colóquelo en una torre adyacente, de modo que
+ la construcción resultante no tiene más de 5 de altura.
+
+p.
+ Cuando no es posible realizar más movimientos, el juego termina.
+ El ganador es el jugador con más torres de su color (arriba).
+
+h3 Más información
+
+p
+ | Hay pocos recursos en línea sobre este juego. Se explican las reglas
+ | por ejemplo en
+ a(href="http://jeuxstrategie.free.fr/Avalam_complet.php") cette page
+ | . Consulte también la página de Avalam en
+ a(href="https://www.jeuxdenim.be/jeu-Avalam") jeuxdenim.be
+ | .
+
+p Inventor: Philippe Deweys (1995)
p.boxed
- | TODO
+ | Empilez librement les tours, de manière à ce que votre couleur
+ | apparaisse en haut.
+
+p.
+ 48 pièces sont initialement réparties sur un plateau irrégulier de 49 cases.
+ Les "blancs" prennent les pièces jaunes,
+ et les "noirs" jouent avec les rouges.
+
+figure.diagram-container
+ .diagram
+ | fen:xxBbxxxxx/xBbBbxxxx/xbBbBbBxx/xBbBbBbBb/BbBb1bBbB/bBbBbBbBx/xxBbBbBbx/xxxxbBbBx/xxxxxbBxx:
+ figcaption Position initiale déterministe.
+
+p.
+ À chaque tour, prenez n'importe quelle tour de moins de 5 pièces (le nombre
+ indiqué dessus) et placez la sur une tour adjacente, de manière à ce que
+ la construction résultante soit de hauteur au plus 5.
+
+p.
+ Quand plus aucun coup n'est possible, la partie s'achève.
+ Le gagnant est le joueur ayant le plus de tours de sa couleur (en haut).
+
+h3 Plus d'information
+
+p
+ | Peu de ressources en ligne à propos de ce jeu. Les règles sont expliquées
+ | par exemple sur
+ a(href="http://jeuxstrategie.free.fr/Avalam_complet.php") cette page
+ | . Voir aussi la page Avalam sur
+ a(href="https://www.jeuxdenim.be/jeu-Avalam") jeuxdenim.be
+ | .
+
+p Inventeur : Philippe Deweys (1995)
p.boxed
- | TODO
+ | Move towers freely on top of each others,
+ | so that your color appears on top.
+
+p
+ a(href="/#/variants/Avalam1") Avalam1
+ | rules, on a regular 8x8 chess board.
p.boxed
- | TODO
+ | Apila libremente las torres, para que tu color
+ | aparece en la parte superior.
+
+p
+ | Reglas de
+ a(href="/#/variants/Avalam1") Avalam1
+ | , en un tablero de Ajedrez 8x8 estándar.
p.boxed
- | TODO
+ | Empilez librement les tours, de manière à ce que votre couleur
+ | apparaisse en haut.
+
+p
+ | Règles d'
+ a(href="/#/variants/Avalam1") Avalam1
+ | , sur un échiquier 8x8 standard.
p.boxed
| Similar to Checkers, with prisoners stacked below capturers.
+figure.diagram-container
+ img.img-center(src="/variants/Emergo/match_2004_U-con.jpg")
+ figcaption.text-center.
+ Game played on an orthogonal depiction of a standard 9x9 Emergo board.
+
+p
+ | Nothing disappears in this game: captured pieces become part of the
+ | capturing unit. Therefore, a piece or unit will always be understood
+ | as a combination of W white (elementary) pieces and B (elementary) black
+ | ones, with
+ br
+ | W >= 0, B >= 0 and W + B >= 1.
+
p
| The 9x9 board is initially empty.
| Each player receives 12 stackable pieces, "in hand".
- | At each turn, a player must either
+ | At each turn, a player must pick an action among the followings:
ul
- li.
- Enter a new piece on the board such that the opponent cannot capture it.
- However, if a capture is already possible before the move, then
- the piece can be dropped anywhere.
- White cannot place a piece in the center at move 1.
- li Play a move on the board, along diagonals.
+ li Enter a new piece (W + B = 1) on the board.
+ li Move a unit along diagonals, by one square.
+ li Capture something.
+
+h3 Entering moves
+
+p.
+ Introducing a piece such that the opponent can take it on next turn is
+ forbidden, unless another capture is already available.
+
+p At first move, white cannot place a piece at the central point.
+
+p.
+ If the opponent already placed all his pieces in hand, then a
+ "shadow piece" enters, formed by all the remaining units available
+ (thus in this case W + B > 1).
+
+h3 Captures
p.
- Simple moves are Ferz moves: one step diagonally.
Captures work exactly as in Checkers: by jumping over a diagonally adjacent
piece to land on a free square just behind.
- However, the resulting situation is more complex. See below.
If a capture is possible, then it must be played; in this case no piece can
be introduced on the board.
+ If after a capture another is possible with the same piece, it must also be
+ played — except if that implies turning at 180 degrees.
-p TODO: diagram
+figure.diagram-container
+ .diagram.diag12
+ | fen:9/9/2a@1a@4/9/4a@4/3D@5/9/5A@3/6b@2 e3:
+ .diagram.diag22
+ | fen:9/9/2a@1a@4/9/4a@4/3D@5/4ba4/9/9:
+ figcaption.
+ Before and after black captures, jumping at the marked location.
+ The next white piece must be captured too.
p.
- Let us consider each unit as a compound entity containing W white pieces
- and B black ones (initially W = 1 and B = 0 for white units,
- and vice-versa for black).
- Captures can then be described formally as follows.
-
-p.
- As white:
- If W1/B1 jumps over W2/B2 at square S2 to land on S1', then
- W1/(B1+1) arrives on S1' and W2/(B2-1) remains on S2.
+ Captures can be described formally as follows.
+ If, as white, W1/B1 jumps over W2/B2 at square S2 to land on S1', then
+ W1/(B1+1) arrives on S1' while W2/(B2-1) stays on S2.
If W2 = B2 - 1 = 0, nothing remains at the captured unit location.
- As black: exchange W and B above.
+ As black: exchange W and B.
p.
In other words, each unit is a stack of friendly and enemy pieces, with
friendly pieces on top. After each capture, the prisoners part of the
- stack is incremented, while the "jailers" counterpart at the captured
+ stack is incremented, while the jailers quantity at the captured
location decreases by one.
p.
When several capturing chains are available,
- the player has to select one of the longest (as in Checkers).
+ the player must select one of the longest (as in Checkers):
+
+figure.diagram-container
+ .diagram
+ | fen:9/9/2a@1a@4/9/2bb1a@4/3C@5/9/9/9:
+ figcaption.
+ From https://www.mindsports.nl/:
+ White's only option is to capture clockwise.
-p TODO: diagram (from mindsports.nl)
+p.
+ A piece can be jumped over several times, as long as it contains
+ at least one enemy unit (controling it).
h3 More information
p
- | See the
+ | You are invited to visit the
a(href="https://www.mindsports.nl/index.php/arena/emergo/88-rules")
- | Emergo page
- | on the author's website.
- | Rules are also described on
+ | authors' website
+ | . The rules are also described on
a(href="http://www.iggamecenter.com/info/en/emergo.html") iggamecenter
- | , where you can also play this game.
+ | , where you can play Emergo.
p Inventors: Christian Freeling and Ed van Zon (1986)
p.boxed
- | TODO
+ | Similar a las Damas, con prisioneros apilados debajo de los captores.
+
+figure.diagram-container
+ img.img-center(src="/variants/Emergo/match_2004_U-con.jpg")
+ figcaption.text-center.
+ Juego jugado en una representación ortogonal
+ de un tablero de Emergo estándar 9x9.
+
+p
+ | Nada desaparece en este juego: las piezas capturadas forman parte de las
+ | capturando unidades. Por lo tanto, una pieza o unidad siempre estará
+ | entendido como una combinación de W piezas blancas (elementales) y
+ | B piezas negras (elementales), con
+ br
+ | W >= 0, B >= 0 y W + B >= 1.
+
+p
+ | El tablero de 9x9 está inicialmente vacío.
+ | Cada jugador recibe 12 piezas apilables, "en la mano".
+ | En cada turno, un jugador debe elegir una de las siguientes acciones:
+ ul
+ li Introduzca una nueva pieza (W + B = 1) en el tablero.
+ li Mueve una unidad un cuadrado a lo largo de las diagonales.
+ li Capture algo.
+
+h3 Jugadas de introducción
+
+p.
+ Está prohibido introducir una pieza de forma que el oponente pueda
+ capturarlo en el siguiente turno, a menos que una captura ya fuera posible.
+
+p.
+ En el primer movimiento, las blancas no pueden colocar una pieza al
+ punto central.
+
+p.
+ Si el oponente ya ha colocado todas sus piezas en la mano, entonces
+ "pieza sombra" entra en el juego, que consta de todas las unidades
+ disponibles (así, en este caso, W + B > 1).
+
+h3 Capturas
+
+p.
+ Las capturas se realizan exactamente como en las Damas: saltando una pieza
+ diagonalmente adyacente para caer en una casilla vacía justo detrás.
+ Si una captura es posible, entonces debe jugarse; en este caso
+ ninguna pieza puede colocarse en el tablero.
+ Si después de una captura es posible otra con la misma pieza, entonces
+ debe ser jugado — a menos que implique un giro de 180 grados.
+
+figure.diagram-container
+ .diagram.diag12
+ | fen:9/9/2a@1a@4/9/4a@4/3D@5/9/5A@3/6b@2 e3:
+ .diagram.diag22
+ | fen:9/9/2a@1a@4/9/4a@4/3D@5/4ba4/9/9:
+ figcaption.
+ Antes y después de las capturas negras,
+ saltando a la ubicación marcada.
+ Tambien hay que capturar la unidad blanca siguente.
+
+p.
+ Las capturas pueden describirse formalmente como sigue.
+ Si, controlado por las blancas, W1/B1 salta sobre W2/B2 ubicado en S2 para
+ aterriza en S1', luego W1/(B1+1) llega a S1' mientras W2/(B2-1) permanece
+ en S2. Si W2 = B2 - 1 = 0, entonces no queda nada en la ubicación del
+ pieza capturada.
+ Para una pieza negra, invierta W y B.
+
+p.
+ En otras palabras, cada unidad está formada por una pila de piezas
+ (elementales) amigas o enemigas, las amigas se encuentran arriba.
+ Después de cada captura, los prisioneros en la pila aumentan en uno,
+ mientras que el número de carceleros en el lugar de captura se reduce en uno.
+
+p.
+ Cuando un jugador tiene varias cadenas de capturas disponibles, debe
+ seleccione uno de los más largos (como en Damas):
+
+figure.diagram-container
+ .diagram
+ | fen:9/9/2a@1a@4/9/2bb1a@4/3C@5/9/9/9:
+ figcaption.
+ En https://www.mindsports.nl/:
+ las blancas deben capturar en sentido horario.
+
+p.
+ Puede saltar sobre una pieza varias veces, siempre que
+ contiene al menos una unidad enemiga (que la controla).
+
+h3 Más información
+
+p
+ | Le invitamos a visitar el
+ a(href="https://www.mindsports.nl/index.php/arena/emergo/88-rules")
+ | sitio de autores
+ | . Las reglas también se describen en
+ a(href="http://www.iggamecenter.com/info/en/emergo.html") iggamecenter
+ | , donde puedes jugar Emergo.
+
+p Inventores: Christian Freeling y Ed van Zon (1986)
p.boxed
- | TODO
+ | Similaires aux Dames, avec des prisonniers empilés sous les captureurs.
+
+figure.diagram-container
+ img.img-center(src="/variants/Emergo/match_2004_U-con.jpg")
+ figcaption.text-center.
+ Partie jouée sur une représentation orthogonale
+ d'un plateau d'Emergo standard 9x9.
+
+p
+ | Rien ne disparaît dans ce jeu : les pièces capturées font ensuite partie
+ | des unités capturantes. Par conséquent, une pièce ou unité sera toujours
+ | compris comme une combinaison de W pièces (élémentaires) blanches et de
+ | B pièces noires (élémentaires), avec
+ br
+ | W >= 0, B >= 0 et W + B >= 1.
+
+p
+ | Le plateau 9x9 est initialement vide.
+ | Chaque joueur reçoit 12 pièces empilables, "en main".
+ | À chaque tour, un jour doit choisir une action parmi les suivantes :
+ ul
+ li Entrer une nouvelle pièce (W + B = 1) sur le plateau.
+ li Déplacer une unité d'une case le long des diagonales.
+ li Capturer quelque chose.
+
+h3 Coups d'introduction
+
+p.
+ Il est interdit d'entrer une pièce de telle façon que l'adversaire puisse
+ la capturer au tour suivant, à moins qu'une capture était déjà possible.
+
+p Au premier coup, les blancs ne peuvent pas poser de pièce au point central.
+
+p.
+ Si l'adversaire a déjà posé toutes ses pièces en main, alors une
+ "pièce ombre" entre dans le jeu, constituée de toutes les unités disponibles
+ (ainsi dans ce cas W + B > 1).
+
+h3 Captures
+
+p.
+ Les captures se déroulent exactement comme aux Dames : en sautant par dessus
+ une pièce diagonalement adjacente pour atterrir sur une case vide juste
+ derrière.
+ Si une capture est possible, alors elle doit être jouée ; dans ce cas
+ aucune pièce ne peut être introduite sur le plateau.
+ Si après une capture une autre est possible avec la même pièce, alors elle
+ doit être jouée — sauf si cela implique un virage à 180 degrés.
+
+figure.diagram-container
+ .diagram.diag12
+ | fen:9/9/2a@1a@4/9/4a@4/3D@5/9/5A@3/6b@2 e3:
+ .diagram.diag22
+ | fen:9/9/2a@1a@4/9/4a@4/3D@5/4ba4/9/9:
+ figcaption.
+ Avant et après que les noirs capturent,
+ sautant à l'emplacement marqué.
+ Il faut aussi capturer la pièce blanche suivante.
+
+p.
+ Les captures peuvent être décrites formellement comme suit.
+ Si, contrôlée par les blancs, W1/B1 saute par dessus W2/B2 situé en S2 pour
+ atterrir en S1', alors W1/(B1+1) arrive en S1' tandis que W2/(B2-1) reste
+ en S2. Si W2 = B2 - 1 = 0, alors rien ne subsiste à l'emplacement de la
+ pièce capturée.
+ Pour une pièce noire, inverser W et B.
+
+p.
+ En d'autres termes, chaque unité est composée d'une pile de pièces
+ (élémentaires) amies ou ennemies, les amies étant situées au dessus.
+ Après chaque capture, les prisonniers dans la pile sont augmentés d'un,
+ tandis que le nombre de geôliers à l'emplacement de la capture diminue d'un.
+
+p.
+ Quand un joueur a à disposition plusieurs chaînes de captures, il doit
+ sélectionner l'une des plus longues (comme aux Dames) :
+
+figure.diagram-container
+ .diagram
+ | fen:9/9/2a@1a@4/9/2bb1a@4/3C@5/9/9/9:
+ figcaption.
+ Sur https://www.mindsports.nl/ :
+ les blancs doivent capturer dans le sens horaire.
+
+p.
+ On peut sauter par dessus une pièce plusieurs fois, du moment qu'elle
+ contient au moins une unité ennemie (qui la contrôle).
+
+h3 Plus d'information
+
+p
+ | Vous êtes invités à visiter le
+ a(href="https://www.mindsports.nl/index.php/arena/emergo/88-rules")
+ | site des auteurs
+ | . Les règles sont également décrites sur
+ a(href="http://www.iggamecenter.com/info/en/emergo.html") iggamecenter
+ | , où vous pouvez jouer à Emergo.
+
+p Inventeurs : Christian Freeling et Ed van Zon (1986)
--- /dev/null
+import { ChessRules } from "@/base_rules";
+import { Avalam2Rules } from "@/variants/Avalam2";
+
+export class Avalam1Rules extends Avalam2Rules {
+
+ static get NOTHING() {
+ return "xx";
+ }
+
+ static board2fen(b) {
+ if (b[0] == 'x') return 'x';
+ return ChessRules.board2fen(b);
+ }
+
+ static fen2board(f) {
+ if (f == 'x') return V.NOTHING;
+ return ChessRules.fen2board(f);
+ }
+
+ getPpath(b) {
+ if (b[0] == 'x') return "Omega/nothing";
+ return "Avalam/" + b;
+ }
+
+ static GenRandInitFen() {
+ return (
+ "xxBbxxxxx/xBbBbxxxx/xbBbBbBxx/xBbBbBbBb/BbBb1bBbB/" +
+ "bBbBbBbBx/xxBbBbBbx/xxxxbBbBx/xxxxxbBxx w 0"
+ );
+ }
+
+ static get size() {
+ return { x: 9, y: 9 };
+ }
+
+ static OnBoard(x, y) {
+ if (!ChessRules.OnBoard(x, y)) return false;
+ switch (x) {
+ case 0: return [2, 3].includes(y);
+ case 1: return [1, 2, 3, 4].includes(y);
+ case 2: return [1, 2, 3, 4, 5, 6].includes(y);
+ case 3: return y >= 1;
+ case 4: return y != 4;
+ case 5: return y <= 7;
+ case 6: return [2, 3, 4, 5, 6, 7].includes(y);
+ case 7: return [4, 5, 6, 7].includes(y);
+ case 8: return [5, 6].includes(y);
+ }
+ return false; //never reached
+ }
+
+};
--- /dev/null
+import { ChessRules, Move, PiPo } from "@/base_rules";
+import { randInt } from "@/utils/alea";
+
+export class Avalam2Rules extends ChessRules {
+
+ static get HasFlags() {
+ return false;
+ }
+
+ static get HasEnpassant() {
+ return false;
+ }
+
+ static get Monochrome() {
+ return true;
+ }
+
+ get showFirstTurn() {
+ return true;
+ }
+
+ getPpath(b) {
+ return "Avalam/" + b;
+ }
+
+ static get PIECES() {
+ // Towers of 1, 2, 3, 4 and 5
+ return ['b', 'c', 'd', 'e', 'f'];
+ }
+
+ static IsGoodPosition(position) {
+ if (position.length == 0) return false;
+ const rows = position.split("/");
+ if (rows.length != V.size.x) return false;
+ for (let row of rows) {
+ let sumElts = 0;
+ for (let i = 0; i < row.length; i++) {
+ if (['x'].concat(V.PIECES).includes(row[i].toLowerCase())) sumElts++;
+ else {
+ const num = parseInt(row[i], 10);
+ if (isNaN(num)) return false;
+ sumElts += num;
+ }
+ }
+ if (sumElts != V.size.y) return false;
+ }
+ return true;
+ }
+
+ static GenRandInitFen() {
+ return (
+ "BbBbBbBb/bBbBbBbB/BbBbBbBb/bBbBbBbB/" +
+ "BbBbBbBb/bBbBbBbB/BbBbBbBb/bBbBbBbB w 0"
+ );
+ }
+
+ canIplay(side) {
+ return this.turn == side;
+ }
+
+ getColor() {
+ return this.turn; //:-)
+ }
+
+ getBasicMove([x1, y1], [x2, y2]) {
+ const cp1 = this.board[x1][y1],
+ cp2 = this.board[x2][y2];
+ const newPiece =
+ String.fromCharCode(cp1.charCodeAt(1) + cp2.charCodeAt(1) - 97);
+ return (
+ new Move({
+ vanish: [
+ new PiPo({ x: x1, y: y1, c: cp1[0], p: cp1[1] }),
+ new PiPo({ x: x2, y: y2, c: cp2[0], p: cp2[1] })
+ ],
+ appear: [
+ new PiPo({ x: x2, y: y2, c: cp1[0], p: newPiece })
+ ]
+ })
+ );
+ }
+
+ getPotentialMovesFrom([x, y]) {
+ const height = this.board[x][y].charCodeAt(1) - 97;
+ if (height == 5) return [];
+ let moves = [];
+ for (let s of V.steps[V.ROOK].concat(V.steps[V.BISHOP])) {
+ const [i, j] = [x + s[0], y + s[1]];
+ if (
+ V.OnBoard(i, j) &&
+ this.board[i][j] != V.EMPTY &&
+ (height + this.board[i][j].charCodeAt(1) - 97 <= 5)
+ ) {
+ moves.push(this.getBasicMove([x, y], [i, j]));
+ }
+ }
+ return moves;
+ }
+
+ filterValid(moves) {
+ return moves;
+ }
+
+ getCheckSquares() {
+ return [];
+ }
+
+ getCurrentScore() {
+ let towersCount = { w: 0, b: 0 };
+ for (let i = 0; i < V.size.x; i++) {
+ for (let j = 0; j < V.size.y; j++) {
+ if (this.board[i][j] != V.EMPTY) {
+ if (this.getPotentialMovesFrom([i, j]).length > 0) return '*';
+ towersCount[ this.board[i][j][0] ]++;
+ }
+ }
+ }
+ if (towersCount['w'] > towersCount['b']) return "1-0";
+ if (towersCount['b'] > towersCount['w']) return "0-1";
+ return "1/2";
+ }
+
+ getComputerMove() {
+ // Random mover (TODO)
+ const moves = super.getAllValidMoves();
+ if (moves.length == 0) return null;
+ return moves[randInt(moves.length)];
+ }
+
+};
return true;
}
+ get showFirstTurn() {
+ return true;
+ }
+
static IsGoodFen(fen) {
if (!ChessRules.IsGoodFen(fen)) return false;
const fenParsed = V.ParseFen(fen);
setOtherVariables(fen) {
const reserve =
V.ParseFen(fen).reserve.split(",").map(x => parseInt(x, 10));
- this.reserve = {
- w: { [V.PAWN]: reserve[0] },
- b: { [V.PAWN]: reserve[1] }
- };
+ this.reserve = { w: null, b: null };
+ if (reserve[0] > 0) this.reserve['w'] = { [V.PAWN]: reserve[0] };
+ if (reserve[1] > 0) this.reserve['b'] = { [V.PAWN]: reserve[1] };
// Local stack of captures during a turn (squares + directions)
this.captures = [ [] ];
}
- atLeastOneCaptureFrom([x, y], color) {
+ atLeastOneCaptureFrom([x, y], color, forbiddenStep) {
for (let s of V.steps[V.BISHOP]) {
- const [i, j] = [x + s[0], y + s[1]];
if (
- V.OnBoard(i + s[0], j + s[1]) &&
- this.board[i][j] != V.EMPTY &&
- this.getColor(i, j) != color &&
- this.board[i + s[0]][j + s[1]] == V.EMPTY
+ !forbiddenStep ||
+ (s[0] != -forbiddenStep[0] || s[1] != -forbiddenStep[1])
) {
- return true;
+ const [i, j] = [x + s[0], y + s[1]];
+ if (
+ V.OnBoard(i + s[0], j + s[1]) &&
+ this.board[i][j] != V.EMPTY &&
+ this.getColor(i, j) != color &&
+ this.board[i + s[0]][j + s[1]] == V.EMPTY
+ ) {
+ return true;
+ }
}
}
return false;
const L0 = this.captures.length;
const captures = this.captures[L0 - 1];
const L = captures.length;
- if (L > 0) return this.atLeastOneCaptureFrom(captures[L-1].square, color);
+ if (L > 0) {
+ return (
+ this.atLeastOneCaptureFrom(
+ captures[L-1].square, color, captures[L-1].step)
+ );
+ }
for (let i = 0; i < V.size.x; i++) {
for (let j=0; j< V.size.y; j++) {
if (
return res;
};
+ getLongestCaptures_aux([x, y], color, locSteps) {
+ let res = [];
+ const L = locSteps.length;
+ const lastStep = (L > 0 ? locSteps[L-1] : null);
+ for (let s of V.steps[V.BISHOP]) {
+ if (!!lastStep && s[0] == -lastStep[0] && s[1] == -lastStep[1]) continue;
+ const [i, j] = [x + s[0], y + s[1]];
+ if (
+ V.OnBoard(i + s[0], j + s[1]) &&
+ this.board[i + s[0]][j + s[1]] == V.EMPTY &&
+ this.board[i][j] != V.EMPTY &&
+ this.getColor(i, j) != color
+ ) {
+ const move = this.getBasicMove([x, y], [i + s[0], j + s[1]], [i, j]);
+ locSteps.push(s);
+ V.PlayOnBoard(this.board, move);
+ const nextRes =
+ this.getLongestCaptures_aux([i + s[0], j + s[1]], color, locSteps);
+ res.push(1 + nextRes);
+ locSteps.pop();
+ V.UndoOnBoard(this.board, move);
+ }
+ }
+ if (res.length == 0) return 0;
+ return Math.max(...res);
+ }
+
getLongestCapturesFrom([x, y], color, locSteps) {
- //
- // TODO: debug here, from
- // 9/9/2a@1a@4/5A@3/9/3aa1A@3/9/9/8A@ w 10 8,9
- // White to move, double capture.
- //
let res = [];
const L = locSteps.length;
const lastStep = (L > 0 ? locSteps[L-1] : null);
const move = this.getBasicMove([x, y], [i + s[0], j + s[1]], [i, j]);
locSteps.push(s);
V.PlayOnBoard(this.board, move);
- const sRes = this.getLongestCapturesFrom(
- [i + s[0], j + s[1]], color, locSteps);
- res.push({
- step: s,
- length: 1 + (sRes.length == 0 ? 0 : sRes[0].length)
- });
+ const stepRes =
+ this.getLongestCaptures_aux([i + s[0], j + s[1]], color, locSteps);
+ res.push({ step: s, length: 1 + stepRes });
locSteps.pop();
V.UndoOnBoard(this.board, move);
}
}
- return this.maxLengthIndices(res).map(i => res[i]);
+ return this.maxLengthIndices(res).map(i => res[i]);;
}
getAllLongestCaptures(color) {
const L0 = this.captures.length;
const captures = this.captures[L0 - 1];
const L = captures.length;
+ let caps = [];
if (L > 0) {
- let locSteps = [];
- const caps = Object.assign(
- { square: captures[L-1].square },
- this.getLongestCapturesFrom(captures[L-1].square, color, locSteps)
+ let locSteps = [ captures[L-1].step ];
+ let res =
+ this.getLongestCapturesFrom(captures[L-1].square, color, locSteps);
+ Array.prototype.push.apply(
+ caps,
+ res.map(r => Object.assign({ square: captures[L-1].square }, r))
);
- return this.maxLengthIndices(caps).map(i => caps[i]);
}
- let caps = [];
- for (let i = 0; i < V.size.x; i++) {
- for (let j=0; j < V.size.y; j++) {
- if (
- this.board[i][j] != V.EMPTY &&
- this.getColor(i, j) == color
- ) {
- let locSteps = [];
- let res = this.getLongestCapturesFrom([i, j], color, locSteps);
- Array.prototype.push.apply(
- caps,
- res.map(r => Object.assign({ square: [i, j] }, r))
- );
+ else {
+ for (let i = 0; i < V.size.x; i++) {
+ for (let j=0; j < V.size.y; j++) {
+ if (
+ this.board[i][j] != V.EMPTY &&
+ this.getColor(i, j) == color
+ ) {
+ let locSteps = [];
+ let res = this.getLongestCapturesFrom([i, j], color, locSteps);
+ Array.prototype.push.apply(
+ caps,
+ res.map(r => Object.assign({ square: [i, j] }, r))
+ );
+ }
}
}
}
-
-console.log(caps);
-
return this.maxLengthIndices(caps).map(i => caps[i]);
}
});
}
// Compute resulting types based on jumped + jumping pieces
+ const color = this.getColor(x1, y1);
+ const firstCodes = (color == 'w' ? [65, 97] : [97, 65]);
const cpCapt = this.board[capt[0]][capt[1]];
- const newAtCapt = cpCapt.charCodeAt(0) - 1;
- const newAtDest =
- cp1[1] == '@'
- ? (cp1.charCodeAt(0) < 97 ? 65 : 97)
- : (cp1.charCodeAt(1) + 1);
- const color = this.turn;
+ let count1 = [cp1.charCodeAt(0) - firstCodes[0], -1];
+ if (cp1[1] != '@') count1[1] = cp1.charCodeAt(1) - firstCodes[0];
+ let countC = [cpCapt.charCodeAt(0) - firstCodes[1], -1];
+ if (cpCapt[1] != '@') countC[1] = cpCapt.charCodeAt(1) - firstCodes[1];
+ count1[1]++;
+ countC[0]--;
+ let colorChange = false,
+ captVanish = false;
+ if (countC[0] < 0) {
+ if (countC[1] >= 0) {
+ colorChange = true;
+ countC = [countC[1], -1];
+ }
+ else captVanish = true;
+ }
+ const incPrisoners = String.fromCharCode(firstCodes[0] + count1[1]);
let mv = new Move({
appear: [
new PiPo({
x: x2,
y: y2,
c: cp1[0],
- p: String.fromCharCode(newAtDest)
+ p: incPrisoners
})
],
vanish: [
new PiPo({ x: capt[0], y: capt[1], c: cpCapt[0], p: cpCapt[1] })
]
});
- if ([64, 96].includes(newAtCapt)) {
- // Enemy units vanish from capturing square
- if (cpCapt.charAt(1) != '@') {
- // Out units remain:
- mv.appear.push(
- new PiPo({
- x: capt[0],
- y: capt[1],
- c: cpCapt[0],
- p: '@'
- })
- );
- }
- }
- else {
+ if (!captVanish) {
mv.appear.push(
new PiPo({
x: capt[0],
y: capt[1],
- c: String.fromCharCode(newAtCapt),
- p: cpCapt[1]
+ c: String.fromCharCode(
+ firstCodes[(colorChange ? 0 : 1)] + countC[0]),
+ p: (colorChange ? '@' : cpCapt[1]),
})
);
}
const L0 = this.captures.length;
let captures = this.captures[L0 - 1];
captures.push({
- square: [move.start.x, move.start.y],
- step: [move.end.x - move.start.x, move.end.y - move.start.y]
+ square: [move.end.x, move.end.y],
+ step: [(move.end.x - move.start.x)/2, (move.end.y - move.start.y)/2]
});
- if (this.atLeastOneCapture())
- // There could be other captures (optional)
+ if (this.atLeastOneCapture(color))
+ // There could be other captures (mandatory)
move.notTheEnd = true;
}
else if (move.vanish == 0) {
}
atLeastOneMove() {
- if (this.atLeastOneCapture()) return true;
const color = this.turn;
+ if (this.atLeastOneCapture(color)) return true;
for (let i = 0; i < V.size.x; i++) {
for (let j = 0; j < V.size.y; j++) {
if (this.board[i][j] != V.EMPTY && this.getColor(i, j) == color) {
getCurrentScore() {
const color = this.turn;
// If no pieces on board + reserve, I lose
- if (
- !this.reserve[color] &&
- this.board.every(b => {
- return b.every(cell => {
- return (cell == "" || cell[0] != color);
- });
- })
- ) {
- return (color == 'w' ? "0-1" : "1-0");
+ if (!!this.reserve[color]) return "*";
+ let atLeastOnePiece = false;
+ outerLoop: for (let i=0; i < V.size.x; i++) {
+ for (let j=0; j < V.size.y; j++) {
+ if (this.board[i][j] != V.EMPTY && this.getColor(i, j) == color) {
+ atLeastOnePiece = true;
+ break outerLoop;
+ }
+ }
}
+ if (!atLeastOnePiece) return (color == 'w' ? "0-1" : "1-0");
if (!this.atLeastOneMove()) return "1/2";
return "*";
}
getNotation(move) {
if (move.vanish.length == 0) return "@" + V.CoordsToSquare(move.end);
+ const L0 = this.captures.length;
+ if (this.captures[L0 - 1].length > 0) return V.CoordsToSquare(move.end);
return V.CoordsToSquare(move.start) + V.CoordsToSquare(move.end);
}