diff --git a/locale-src/de/apgames.json b/locale-src/de/apgames.json index acc69d3e..a36e384d 100644 --- a/locale-src/de/apgames.json +++ b/locale-src/de/apgames.json @@ -640,8 +640,8 @@ "out": "Der Spieler mit der größten kleinsten Gruppe gewinnt das Spiel." }, "descriptions.mirador": { - "src": "Mirador is a fast and exhilarating connection game played on a 27 x 27 square grid by placing 2 x 2 squares to represent watchtowers. It uses line-of-sight connections and equivalent goals (making it more of a race than a pure connection game).", - "out": "Mirador ist ein schnelles und aufregendes Verbindungsspiel auf einem 27 x 27 Quadratgitter, bei dem 2 x 2 Quadrate platziert werden, die Wachtürme darstellen. Es nutzt Sichtlinienverbindungen und gleichwertige Ziele (was es eher zu einem Rennen als zu einem reinen Verbindungsspiel macht)." + "src": "Mirador is a fast and exhilarating connection game played on a square grid (28 x 28 by default) by placing 2 x 2 squares to represent watchtowers. It uses line-of-sight connections and equivalent goals (making it more of a race than a pure connection game).", + "out": "Mirador ist ein schnelles und aufregendes Verbindungsspiel, das auf einem quadratischen Raster (standardmäßig 28 x 28) gespielt wird, indem 2 x 2-Quadrate platziert werden, die Wachtürme darstellen. Es nutzt Sichtlinienverbindungen und gleichwertige Ziele (was es eher zu einem Rennen als zu einem reinen Verbindungsspiel macht)." }, "descriptions.mixtour": { "src": "Two players create towers with the goal of creating a tower at least five high with your colour at the top. The twist here is two-fold: (1) you can move opponent's pieces and (2) movement range is determined by the *target* stack height and not the moving stack height.", @@ -3331,6 +3331,10 @@ "src": "Maneuverability is a measure of how close your pieces are to promoting. Your maximum maneuverability is the board size times the number of stacks you control.\n\nMaterial is calculated by giving you a point for every friendly piece in a stack you control, plus an extra point if you have an officer on top of that stack.", "out": "Manövrierfähigkeit ist ein Maß dafür, wie nah deine Steine an der Umwandlung sind. Deine maximale Manövrierfähigkeit entspricht der Brettgröße multipliziert mit der Anzahl der Stapel, die du kontrollierst.\n\nMaterial wird berechnet, indem du einen Punkt für jeden eigenen Stein in einem von dir kontrollierten Stapel erhältst, plus einen Extra-Punkt, wenn sich ein Offizier an der Spitze dieses Stapels befindet." }, + "notes.lielow": { + "src": "\"Moves until suicide\" totals for each player how many moves each of their stacks could still make — growing by one each move and always choosing the direction that survives longest — before being forced to bear off. It ignores every other stack on the board, friendly or enemy, so it's a rough measure of how exposed a player's pieces are, not a count of actual legal moves remaining.", + "out": "\"Züge bis zum Selbstmord\" summiert für jeden Spieler auf, wie viele Züge jeder seiner Stapel noch machen könnte — wobei er mit jedem Zug um eins wächst und immer die Richtung wählt, die am längsten überlebt — bevor er gezwungen ist, abgetragen zu werden. Es ignoriert jeden anderen Stapel auf dem Brett, ob eigene oder gegnerische, daher ist es ein grobes Maß dafür, wie exponiert die Steine eines Spielers sind, und keine Zählung der tatsächlich verbleibenden legalen Züge." + }, "notes.linage": { "src": "Linage is a 2016 game designed by Luis Bolaños Mures. The game is based on the following definitions: A **region** is a maximal set of orthogonally contiguous empty points. A **line** is a set of N orthogonally contiguous empty points on the same row or column (default is N=3); and a region is **owned** by Vertical if it contains no horizontal lines, and by Horizontal if it contains no vertical lines. A region is free if it is owned by neither player. Regions must always have at least one line.\n\nOn his turn, the player passes or places a stone in a free region. The game ends when both players pass in succession, and wins the one with highest score (i.e., the number of points in the regions the player owns, plus komi).", "out": "Linage ist ein Spiel aus dem Jahr 2016 von Luis Bolaños Mures. Das Spiel basiert auf folgenden Definitionen: Eine **Region** ist eine maximale Menge orthogonal zusammenhängender leerer Punkte. Eine **Linie** ist eine Menge von N orthogonal zusammenhängenden leeren Punkten in derselben Reihe oder Spalte (Standard ist N=3); eine Region gehört **Vertikal**, wenn sie keine horizontalen Linien enthält, und **Horizontal**, wenn sie keine vertikalen Linien enthält. Eine Region ist frei, wenn sie keinem der beiden Spieler gehört. Regionen müssen immer mindestens eine Linie enthalten.\n\nIn seinem Zug passt der Spieler oder platziert einen Stein in einer freien Region. Das Spiel endet, wenn beide Spieler nacheinander passen, und es gewinnt derjenige mit der höchsten Punktzahl (d. h. die Anzahl der Punkte in den Regionen, die dem Spieler gehören, plus Komi)." @@ -3811,6 +3815,10 @@ "src": "Maneuverability", "out": "Beweglichkeit" }, + "status.lielow.MOVESUNTILSUICIDE": { + "src": "Moves until suicide", + "out": "Züge bis zum Selbstmord" + }, "status.majorities": { "src": "Scores (─, ⟋, ⟍)", "out": "Punktestände (─, ⟋, ⟍)" @@ -14215,6 +14223,10 @@ "src": "19x19 board", "out": "19x19-Brett" }, + "variants.asli.board-23.name": { + "src": "23x23 board", + "out": "23x23-Brett" + }, "variants.asli.board-27.name": { "src": "27x27 board", "out": "27x27-Brett" @@ -14627,6 +14639,10 @@ "src": "Roughly 12 pieces across", "out": "Ungefähr 12 Steine breit" }, + "variants.calculus.#board.name": { + "src": "Default board", + "out": "Standardbrett" + }, "variants.calculus.width-10.description": { "src": "Roughly 10 pieces across", "out": "Ungefähr 10 Steine breit" @@ -16535,6 +16551,14 @@ "src": "Hexagonal board (base-8)", "out": "Hexagonales Brett (Basis 8)" }, + "variants.mirador.#board.name": { + "src": "28x28 board", + "out": "28x28-Brett" + }, + "variants.mirador.size-40.name": { + "src": "40x40 board", + "out": "40x40-Brett" + }, "variants.mixtour.five.description": { "src": "The winner is the first to score three points.", "out": "Gewinner ist, wer zuerst drei Punkte erzielt." diff --git a/locale-src/es-US/apgames.json b/locale-src/es-US/apgames.json index d9fefa54..712c7e08 100644 --- a/locale-src/es-US/apgames.json +++ b/locale-src/es-US/apgames.json @@ -640,8 +640,8 @@ "out": "El jugador cuyo grupo más pequeño sea el más grande gana el juego." }, "descriptions.mirador": { - "src": "Mirador is a fast and exhilarating connection game played on a 27 x 27 square grid by placing 2 x 2 squares to represent watchtowers. It uses line-of-sight connections and equivalent goals (making it more of a race than a pure connection game).", - "out": "Mirador es un juego de conexión rápido y emocionante que se juega en una cuadrícula de 27 x 27 colocando cuadrados de 2 x 2 para representar torres de vigilancia. Utiliza conexiones por línea de visión y objetivos equivalentes (lo que lo convierte más en una carrera que en un juego de conexión puro)." + "src": "Mirador is a fast and exhilarating connection game played on a square grid (28 x 28 by default) by placing 2 x 2 squares to represent watchtowers. It uses line-of-sight connections and equivalent goals (making it more of a race than a pure connection game).", + "out": "Mirador es un juego de conexión rápido y emocionante que se juega en una cuadrícula cuadrada (de 28 x 28 por defecto) colocando cuadrados de 2 x 2 para representar torres de vigilancia. Usa conexiones por línea de visión y objetivos equivalentes (lo que lo convierte más en una carrera que en un juego de conexión puro)." }, "descriptions.mixtour": { "src": "Two players create towers with the goal of creating a tower at least five high with your colour at the top. The twist here is two-fold: (1) you can move opponent's pieces and (2) movement range is determined by the *target* stack height and not the moving stack height.", @@ -3331,6 +3331,10 @@ "src": "Maneuverability is a measure of how close your pieces are to promoting. Your maximum maneuverability is the board size times the number of stacks you control.\n\nMaterial is calculated by giving you a point for every friendly piece in a stack you control, plus an extra point if you have an officer on top of that stack.", "out": "La maniobrabilidad es una medida de qué tan cerca están tus piezas de coronarse. Tu maniobrabilidad máxima es el tamaño del tablero multiplicado por el número de pilas que controlas.\n\nEl material se calcula dándote un punto por cada pieza propia en una pila que controlas, más un punto extra si tienes un oficial en la parte superior de esa pila." }, + "notes.lielow": { + "src": "\"Moves until suicide\" totals for each player how many moves each of their stacks could still make — growing by one each move and always choosing the direction that survives longest — before being forced to bear off. It ignores every other stack on the board, friendly or enemy, so it's a rough measure of how exposed a player's pieces are, not a count of actual legal moves remaining.", + "out": "\"Movimientos hasta el suicidio\" calcula para cada jugador cuántos movimientos podría realizar aún cada una de sus pilas —creciendo en uno con cada movimiento y eligiendo siempre la dirección que sobreviva más tiempo— antes de verse obligada a retirar piezas. Ignora todas las demás pilas del tablero, ya sean propias o enemigas, por lo que es una medida aproximada de qué tan expuestas están las piezas de un jugador, y no un conteo de los movimientos legales restantes." + }, "notes.linage": { "src": "Linage is a 2016 game designed by Luis Bolaños Mures. The game is based on the following definitions: A **region** is a maximal set of orthogonally contiguous empty points. A **line** is a set of N orthogonally contiguous empty points on the same row or column (default is N=3); and a region is **owned** by Vertical if it contains no horizontal lines, and by Horizontal if it contains no vertical lines. A region is free if it is owned by neither player. Regions must always have at least one line.\n\nOn his turn, the player passes or places a stone in a free region. The game ends when both players pass in succession, and wins the one with highest score (i.e., the number of points in the regions the player owns, plus komi).", "out": "Linage es un juego de 2016 diseñado por Luis Bolaños Mures. El juego se basa en las siguientes definiciones: Una **región** es un conjunto máximo de puntos vacíos contiguos ortogonalmente. Una **línea** es un conjunto de N puntos vacíos contiguos ortogonalmente en la misma fila o columna (por defecto N=3); y una región es **propiedad** de Vertical si no contiene líneas horizontales, y de Horizontal si no contiene líneas verticales. Una región es libre si no pertenece a ningún jugador. Las regiones siempre deben tener al menos una línea.\n\nEn su turno, el jugador pasa o coloca una piedra en una región libre. El juego termina cuando ambos jugadores pasan sucesivamente, y gana quien tenga la puntuación más alta (es decir, el número de puntos en las regiones que posee el jugador, más el komi)." @@ -3811,6 +3815,10 @@ "src": "Maneuverability", "out": "Maniobrabilidad" }, + "status.lielow.MOVESUNTILSUICIDE": { + "src": "Moves until suicide", + "out": "Movimientos hasta el suicidio" + }, "status.majorities": { "src": "Scores (─, ⟋, ⟍)", "out": "Puntuación (─, ⟋, ⟍)" @@ -14215,6 +14223,10 @@ "src": "19x19 board", "out": "Tablero de 19x19" }, + "variants.asli.board-23.name": { + "src": "23x23 board", + "out": "Tablero de 23x23" + }, "variants.asli.board-27.name": { "src": "27x27 board", "out": "Tablero de 27x27" @@ -14627,6 +14639,10 @@ "src": "Roughly 12 pieces across", "out": "Aproximadamente 12 piezas de ancho" }, + "variants.calculus.#board.name": { + "src": "Default board", + "out": "Tablero predeterminado" + }, "variants.calculus.width-10.description": { "src": "Roughly 10 pieces across", "out": "Aproximadamente 10 piezas de ancho" @@ -16535,6 +16551,14 @@ "src": "Hexagonal board (base-8)", "out": "Tablero hexagonal (base 8)" }, + "variants.mirador.#board.name": { + "src": "28x28 board", + "out": "Tablero de 28x28" + }, + "variants.mirador.size-40.name": { + "src": "40x40 board", + "out": "Tablero de 40x40" + }, "variants.mixtour.five.description": { "src": "The winner is the first to score three points.", "out": "El ganador es el primero en anotar tres puntos." diff --git a/locale-src/fr/apgames.json b/locale-src/fr/apgames.json index 985e47c6..2fed1793 100644 --- a/locale-src/fr/apgames.json +++ b/locale-src/fr/apgames.json @@ -640,8 +640,8 @@ "out": "Le joueur ayant le plus grand groupe le plus petit gagne la partie." }, "descriptions.mirador": { - "src": "Mirador is a fast and exhilarating connection game played on a 27 x 27 square grid by placing 2 x 2 squares to represent watchtowers. It uses line-of-sight connections and equivalent goals (making it more of a race than a pure connection game).", - "out": "Mirador est un jeu de connexion rapide et palpitant joué sur une grille carrée de 27 x 27 en plaçant des carrés de 2 x 2 pour représenter des tours de guet. Il utilise des connexions par ligne de vue et des objectifs équivalents (ce qui en fait plus une course qu'un pur jeu de connexion)." + "src": "Mirador is a fast and exhilarating connection game played on a square grid (28 x 28 by default) by placing 2 x 2 squares to represent watchtowers. It uses line-of-sight connections and equivalent goals (making it more of a race than a pure connection game).", + "out": "Mirador est un jeu de connexion rapide et captivant qui se joue sur une grille carrée (28 x 28 par défaut) en plaçant des carrés de 2 x 2 représentant des tours de guet. Il utilise des connexions en ligne de mire et des objectifs équivalents (ce qui en fait davantage une course qu'un pur jeu de connexion)." }, "descriptions.mixtour": { "src": "Two players create towers with the goal of creating a tower at least five high with your colour at the top. The twist here is two-fold: (1) you can move opponent's pieces and (2) movement range is determined by the *target* stack height and not the moving stack height.", @@ -3331,6 +3331,10 @@ "src": "Maneuverability is a measure of how close your pieces are to promoting. Your maximum maneuverability is the board size times the number of stacks you control.\n\nMaterial is calculated by giving you a point for every friendly piece in a stack you control, plus an extra point if you have an officer on top of that stack.", "out": "La manœuvrabilité mesure à quel point vos pièces sont proches de la promotion. Votre manœuvrabilité maximale est égale à la taille du plateau multipliée par le nombre de piles que vous contrôlez.\n\nLe matériel est calculé en vous accordant un point pour chaque pièce alliée dans une pile que vous contrôlez, plus un point supplémentaire si vous avez un officier au sommet de cette pile." }, + "notes.lielow": { + "src": "\"Moves until suicide\" totals for each player how many moves each of their stacks could still make — growing by one each move and always choosing the direction that survives longest — before being forced to bear off. It ignores every other stack on the board, friendly or enemy, so it's a rough measure of how exposed a player's pieces are, not a count of actual legal moves remaining.", + "out": "\"Coups avant suicide\" totalise pour chaque joueur le nombre de coups que chacune de ses piles pourrait encore effectuer — augmentant d'un à chaque coup et choisissant toujours la direction qui survit le plus longtemps — avant d'être contrainte de sortir du plateau. Cet indicateur ignore toutes les autres piles sur le plateau, alliées comme ennemies ; c'est donc une mesure approximative de l'exposition des pièces d'un joueur, et non un décompte des coups légaux réellement restants." + }, "notes.linage": { "src": "Linage is a 2016 game designed by Luis Bolaños Mures. The game is based on the following definitions: A **region** is a maximal set of orthogonally contiguous empty points. A **line** is a set of N orthogonally contiguous empty points on the same row or column (default is N=3); and a region is **owned** by Vertical if it contains no horizontal lines, and by Horizontal if it contains no vertical lines. A region is free if it is owned by neither player. Regions must always have at least one line.\n\nOn his turn, the player passes or places a stone in a free region. The game ends when both players pass in succession, and wins the one with highest score (i.e., the number of points in the regions the player owns, plus komi).", "out": "Linage est un jeu de 2016 conçu par Luis Bolaños Mures. Le jeu repose sur les définitions suivantes : Une **région** est un ensemble maximal de points vides contigus de manière orthogonale. Une **ligne** est un ensemble de N points vides contigus de manière orthogonale sur la même rangée ou colonne (par défaut N=3) ; et une région est **possédée** par Vertical si elle ne contient aucune ligne horizontale, et par Horizontal si elle ne contient aucune ligne verticale. Une région est libre si elle n'appartient à aucun des deux joueurs. Les régions doivent toujours contenir au moins une ligne.\n\nÀ son tour, le joueur passe ou place une pierre dans une région libre. La partie se termine lorsque les deux joueurs passent consécutivement, et le joueur avec le score le plus élevé l'emporte (c'est-à-dire le nombre de points dans les régions que le joueur possède, plus le komi)." @@ -3811,6 +3815,10 @@ "src": "Maneuverability", "out": "Maniabilité" }, + "status.lielow.MOVESUNTILSUICIDE": { + "src": "Moves until suicide", + "out": "Coups avant suicide" + }, "status.majorities": { "src": "Scores (─, ⟋, ⟍)", "out": "Scores (─, ⟋, ⟍)" @@ -14215,6 +14223,10 @@ "src": "19x19 board", "out": "Plateau 19x19" }, + "variants.asli.board-23.name": { + "src": "23x23 board", + "out": "Plateau 23x23" + }, "variants.asli.board-27.name": { "src": "27x27 board", "out": "Plateau 27x27" @@ -14627,6 +14639,10 @@ "src": "Roughly 12 pieces across", "out": "Environ 12 pièces de largeur" }, + "variants.calculus.#board.name": { + "src": "Default board", + "out": "Plateau par défaut" + }, "variants.calculus.width-10.description": { "src": "Roughly 10 pieces across", "out": "Environ 10 pièces de largeur" @@ -16535,6 +16551,14 @@ "src": "Hexagonal board (base-8)", "out": "Plateau hexagonal (base 8)" }, + "variants.mirador.#board.name": { + "src": "28x28 board", + "out": "Plateau 28x28" + }, + "variants.mirador.size-40.name": { + "src": "40x40 board", + "out": "Plateau 40x40" + }, "variants.mixtour.five.description": { "src": "The winner is the first to score three points.", "out": "Le gagnant est le premier à marquer trois points." diff --git a/locale-src/it/apgames.json b/locale-src/it/apgames.json index d9dba894..003cf752 100644 --- a/locale-src/it/apgames.json +++ b/locale-src/it/apgames.json @@ -640,8 +640,8 @@ "out": "Il giocatore con il gruppo più piccolo più grande vince la partita." }, "descriptions.mirador": { - "src": "Mirador is a fast and exhilarating connection game played on a 27 x 27 square grid by placing 2 x 2 squares to represent watchtowers. It uses line-of-sight connections and equivalent goals (making it more of a race than a pure connection game).", - "out": "Mirador è un gioco di connessione veloce ed esaltante giocato su una griglia quadrata 27 x 27 posizionando quadrati 2 x 2 per rappresentare torri di guardia. Utilizza connessioni in linea di vista ed obiettivi equivalenti (rendendolo più una corsa che un puro gioco di connessione)." + "src": "Mirador is a fast and exhilarating connection game played on a square grid (28 x 28 by default) by placing 2 x 2 squares to represent watchtowers. It uses line-of-sight connections and equivalent goals (making it more of a race than a pure connection game).", + "out": "Mirador è un gioco di connessione rapido ed entusiasmante giocato su una griglia quadrata (28 x 28 come impostazione predefinita) piazzando quadrati 2 x 2 per rappresentare torri di guardia. Utilizza connessioni in linea di vista e obiettivi equivalenti (rendendolo più una corsa che un puro gioco di connessione)." }, "descriptions.mixtour": { "src": "Two players create towers with the goal of creating a tower at least five high with your colour at the top. The twist here is two-fold: (1) you can move opponent's pieces and (2) movement range is determined by the *target* stack height and not the moving stack height.", @@ -3331,6 +3331,10 @@ "src": "Maneuverability is a measure of how close your pieces are to promoting. Your maximum maneuverability is the board size times the number of stacks you control.\n\nMaterial is calculated by giving you a point for every friendly piece in a stack you control, plus an extra point if you have an officer on top of that stack.", "out": "La manovrabilità è una misura di quanto i tuoi pezzi siano vicini alla promozione. La tua manovrabilità massima è pari alla dimensione del tabellone moltiplicata per il numero di pile che controlli.\n\nIl materiale viene calcolato assegnandoti un punto per ogni pezzo amico in una pila che controlli, più un punto extra se hai un ufficiale in cima a quella pila." }, + "notes.lielow": { + "src": "\"Moves until suicide\" totals for each player how many moves each of their stacks could still make — growing by one each move and always choosing the direction that survives longest — before being forced to bear off. It ignores every other stack on the board, friendly or enemy, so it's a rough measure of how exposed a player's pieces are, not a count of actual legal moves remaining.", + "out": "\"Mosse fino al suicidio\" calcola per ciascun giocatore quante mosse ciascuna delle sue pile potrebbe ancora compiere — crescendo di uno a ogni mossa e scegliendo sempre la direzione che sopravvive più a lungo — prima di essere costretta a uscire dal tabellone. Ignora ogni altra pila sul tabellone, amica o nemica, quindi è una misura approssimativa di quanto siano esposte le pedine di un giocatore, non un conteggio delle mosse legali effettivamente rimaste." + }, "notes.linage": { "src": "Linage is a 2016 game designed by Luis Bolaños Mures. The game is based on the following definitions: A **region** is a maximal set of orthogonally contiguous empty points. A **line** is a set of N orthogonally contiguous empty points on the same row or column (default is N=3); and a region is **owned** by Vertical if it contains no horizontal lines, and by Horizontal if it contains no vertical lines. A region is free if it is owned by neither player. Regions must always have at least one line.\n\nOn his turn, the player passes or places a stone in a free region. The game ends when both players pass in succession, and wins the one with highest score (i.e., the number of points in the regions the player owns, plus komi).", "out": "Linage è un gioco del 2016 progettato da Luis Bolaños Mures. Il gioco si basa sulle seguenti definizioni: una **regione** è un insieme massimale di punti vuoti ortogonalmente contigui. Una **linea** è un insieme di N punti vuoti ortogonalmente contigui sulla stessa riga o colonna (il valore predefinito è N=3); e una regione è di **proprietà** di Verticale se non contiene linee orizzontali, e di Orizzontale se non contiene linee verticali. Una regione è libera se non appartiene a nessuno dei due giocatori. Le regioni devono sempre contenere almeno una linea.\n\nNel proprio turno, il giocatore passa o posiziona una pedina in una regione libera. La partita termina quando entrambi i giocatori passano consecutivamente, e vince chi ha il punteggio più alto (ovvero il numero di punti nelle regioni possedute dal giocatore, più il komi)." @@ -3811,6 +3815,10 @@ "src": "Maneuverability", "out": "Manovrabilità" }, + "status.lielow.MOVESUNTILSUICIDE": { + "src": "Moves until suicide", + "out": "Mosse fino al suicidio" + }, "status.majorities": { "src": "Scores (─, ⟋, ⟍)", "out": "Punteggi (─, ⟋, ⟍)" @@ -14215,6 +14223,10 @@ "src": "19x19 board", "out": "Tavoliere 19x19" }, + "variants.asli.board-23.name": { + "src": "23x23 board", + "out": "Plancia 23x23" + }, "variants.asli.board-27.name": { "src": "27x27 board", "out": "Tavoliere 27x27" @@ -14627,6 +14639,10 @@ "src": "Roughly 12 pieces across", "out": "Circa 12 pezzi di larghezza" }, + "variants.calculus.#board.name": { + "src": "Default board", + "out": "Scacchiera predefinita" + }, "variants.calculus.width-10.description": { "src": "Roughly 10 pieces across", "out": "Circa 10 pezzi di larghezza" @@ -16535,6 +16551,14 @@ "src": "Hexagonal board (base-8)", "out": "Tabellone esagonale (base 8)" }, + "variants.mirador.#board.name": { + "src": "28x28 board", + "out": "Plancia 28x28" + }, + "variants.mirador.size-40.name": { + "src": "40x40 board", + "out": "Plancia 40x40" + }, "variants.mixtour.five.description": { "src": "The winner is the first to score three points.", "out": "Vince chi ottiene per primo tre punti." diff --git a/locales/de/apgames.json b/locales/de/apgames.json index ae291544..2e3a9da9 100644 --- a/locales/de/apgames.json +++ b/locales/de/apgames.json @@ -156,7 +156,7 @@ "mimic": "Ein Spiel, bei dem gegnerische Figuren Ihre Züge nachahmen, während Sie darum wetten, als erster Spieler die hinterste Reihe zu erreichen.", "minefield": "Verbinden Sie gegenüberliegende Seiten des Bretts, aber bestimmte Figurenkonfigurationen sind verboten.", "minimize": "Der Spieler mit der größten kleinsten Gruppe gewinnt das Spiel.", - "mirador": "Mirador ist ein schnelles und aufregendes Verbindungsspiel auf einem 27 x 27 Quadratgitter, bei dem 2 x 2 Quadrate platziert werden, die Wachtürme darstellen. Es nutzt Sichtlinienverbindungen und gleichwertige Ziele (was es eher zu einem Rennen als zu einem reinen Verbindungsspiel macht).", + "mirador": "Mirador ist ein schnelles und aufregendes Verbindungsspiel, das auf einem quadratischen Raster (standardmäßig 28 x 28) gespielt wird, indem 2 x 2-Quadrate platziert werden, die Wachtürme darstellen. Es nutzt Sichtlinienverbindungen und gleichwertige Ziele (was es eher zu einem Rennen als zu einem reinen Verbindungsspiel macht).", "mixtour": "Zwei Spieler errichten Türme mit dem Ziel, einen Turm von mindestens fünf Höhe mit der eigenen Farbe an der Spitze zu schaffen. Der Clou ist zweifach: (1) Sie können gegnerische Steine bewegen und (2) die Reicheweite der Bewegung wird durch die Höhe des *Zielstapels* und nicht des gezogenen Stapels bestimmt.", "monkey": "Sie beginnen mit einer einzelnen Dame, die aus einem Stapel von Spielsteinen besteht. Bei Zügen ohne Schlagen lässt die Dame einen Einzelstein zurück. Damen und Einzelsteine ziehen und schlagen wie Schachdamen. Um zu gewinnen, schlagen Sie die gegnerische Dame oder lassen Sie dem Gegner keine legalen Züge.", "morphos": "Rein orthogonales Quadrat-Verbindungsspiel. In Ihrem Zug platzieren Sie einen eigenen Stein oder drehen einen gegnerischen Stein in einem von drei vorgegebenen Mustern um. Gewinnen Sie, indem Sie Ihre zwei gegenüberliegenden Seiten des Bretts mit einer Kette aus Steinen Ihrer Farbe verbinden.", @@ -617,6 +617,7 @@ "konane": "Es gibt mehrere konkurrierende Eröffnungsprotokolle, aber das gebräuchlichste Regelwerk ist das Naihe-Regelwerk, das bei Turnieren im Bishop Museum auf Hawaii verwendet und in der BGG-Referenz beschrieben wird. Dieses ist hier implementiert.", "knightline": "Der Einfachheit halber wird dein Stapel beim ersten Klick ungefähr halbiert. Nachfolgende Klicks auf den Quell- oder Zielstapel bewegen jeweils einen Stein. Wenn du fertig bist, klicke auf ein leeres Feld oder verwende die Schaltfläche 'Zug abschließen'.\n\nDas Koordinatensystem ist an das Koordinatensystem des Entwicklers für Hive angepasst, ein Spiel auf einem unbegrenzten (aber dennoch überschaubaren) Sechseckbrett. Die y-Achse ist mit kartesischen Koordinaten (positive und negative ganze Zahlen) beschriftet. Die x-Achse ist mit Buchstaben in alphabetischer Reihenfolge beschriftet, mit dem Ursprung bei (m, 0). Wenn die Bewegung auf der x-Achse die Grenzen des Alphabets in einer der beiden Richtungen überschreitet, wird den Buchstaben ein weiterer Buchstabe vorangestellt (auf z folgt aa, ab, ac usw., und vor a steht zz, zy, zx usw.). Es wird nicht erwartet, dass das Spiel eine Breite erreicht, die mehr Doppelkoordinaten erfordert, aber der Vollständigkeit halber: Auf az folgt ba, vor za steht yz und so weiter. Das Spielbrett kann keine Größe erreichen, die zu Unklarheiten führen würde.", "lasca": "Manövrierfähigkeit ist ein Maß dafür, wie nah deine Steine an der Umwandlung sind. Deine maximale Manövrierfähigkeit entspricht der Brettgröße multipliziert mit der Anzahl der Stapel, die du kontrollierst.\n\nMaterial wird berechnet, indem du einen Punkt für jeden eigenen Stein in einem von dir kontrollierten Stapel erhältst, plus einen Extra-Punkt, wenn sich ein Offizier an der Spitze dieses Stapels befindet.", + "lielow": "\"Züge bis zum Selbstmord\" summiert für jeden Spieler auf, wie viele Züge jeder seiner Stapel noch machen könnte — wobei er mit jedem Zug um eins wächst und immer die Richtung wählt, die am längsten überlebt — bevor er gezwungen ist, abgetragen zu werden. Es ignoriert jeden anderen Stapel auf dem Brett, ob eigene oder gegnerische, daher ist es ein grobes Maß dafür, wie exponiert die Steine eines Spielers sind, und keine Zählung der tatsächlich verbleibenden legalen Züge.", "linage": "Linage ist ein Spiel aus dem Jahr 2016 von Luis Bolaños Mures. Das Spiel basiert auf folgenden Definitionen: Eine **Region** ist eine maximale Menge orthogonal zusammenhängender leerer Punkte. Eine **Linie** ist eine Menge von N orthogonal zusammenhängenden leeren Punkten in derselben Reihe oder Spalte (Standard ist N=3); eine Region gehört **Vertikal**, wenn sie keine horizontalen Linien enthält, und **Horizontal**, wenn sie keine vertikalen Linien enthält. Eine Region ist frei, wenn sie keinem der beiden Spieler gehört. Regionen müssen immer mindestens eine Linie enthalten.\n\nIn seinem Zug passt der Spieler oder platziert einen Stein in einer freien Region. Das Spiel endet, wenn beide Spieler nacheinander passen, und es gewinnt derjenige mit der höchsten Punktzahl (d. h. die Anzahl der Punkte in den Regionen, die dem Spieler gehören, plus Komi).", "loa": "In der Mitte des 9x9-Spielfelds befindet sich ein \"schwarzes Loch\". Die Landung auf dem schwarzen Loch bedeutet, dass der Stein aus dem Spiel entfernt wird. Gleichzeitige Verbindungen werden als Unentschieden gewertet.", "magnate": "Die Terminologie einiger Magnate-Aktionen wurde zur Klarheit und Kürze geändert. Das vollständige Bebauen eines neuen Grundstücks wird als Aktion \"Kaufen\" bezeichnet; der Kauf einer Urkunde für ein neues Grundstück wird als \"Urkunde\" bezeichnet, das Bebauen von Urkunden (also das Hinzufügen von Spielsteinen zu einem Grundstück mit Urkunde, unabhängig davon, ob die Urkunde dadurch vollständig bebaut ist oder nicht) wird als \"Hinzufügen\" bezeichnet. (Das Verkaufen einer Karte und das Tauschen von Farbsymbolen 3 gegen 1 sind unverändert.)\n\nUm den Prozess des Würfelns nach Ressourcen zu beschleunigen, gibt es zwei zusätzliche Aktionen:\n* \"Bevorzugen\" dient zum Festlegen deiner Prämisse, welches Farbsymbol du nehmen möchtest, wenn eine Urkunde beim Wurf deines Gegners auszahlt. Wenn du keine explizite Präferenz festlegst, wählt der Code das seltenere Symbol für dich aus, basierend auf deinen Nicht-Kronen-Farben und deinem aktuellen Symbolvorrat. Das derzeit bevorzugte Symbol ist in der Benutzeroberfläche eingekreist, aber deine persönliche Präferenz ist für den anderen Spieler nie sichtbar.\n* \"Wählen\" ist eine obligatorische erste Aktion zum Sammeln von Farbsymbolen, wenn eine Urkunde bei deinem eigenen Wurf auszahlt. (In allen Fällen, in denen du ein Farbsymbol wählen musst, das sich noch nicht unter deinen Symbolen befindet, klickst du weiterhin auf den entsprechenden Symbolstapel.)\n\nDa du während eines Halbzugs mehrere Aktionen in beliebiger Reihenfolge ausführen kannst, gibt es auch eine Aktion \"Rückgängig\", um deine letzte Aktion zurückzunehmen, unabhängig davon, ob sie abgeschlossen war oder nicht.\n\nBeachte, dass nur das Endergebnis des Ressourcenwürfels angezeigt wird, die Verteilung der erwarteten Ergebnisse jedoch weiterhin der des Würfelns von 2d10 und dem Nehmen des höheren Werts entspricht. Besteuern findet statt, wenn der niedrigere von 2d10 eine 1 ist; ein Farbwürfel wird gewürfelt (oder zwei in der Doppelbesteuerungs-Variante), und die Farben werden unter dem Ressourcenergebnis angezeigt. Der Wurf wird am Ende des Zugs eines Spielers protokolliert und dem nächsten Spieler zugeschrieben (der im physischen Spiel gewürfelt hätte). Außer einem \"Wählen\" ist keine Benutzeraktion erforderlich; Ressourcen werden vom Server zwischen den Zügen automatisch hinzugefügt oder entfernt.\n\nWenn ein Spieler in einem Distrikt führt, ist die Figur oder die Ausrede (Excuse) für diesen Distrikt in der Farbe dieses Spielers umrandet. Die erste Gleichstandspunktzahl (Gesamtwert der Grundstücke) wird in Klammern nach der Distriktpunktzahl angezeigt. Der zweite Gleichstandsentscheid ist die Gesamtzahl der verbleibenden Spielsteine.", @@ -968,6 +969,9 @@ "board-19": { "name": "19x19-Brett" }, + "board-23": { + "name": "23x23-Brett" + }, "board-27": { "name": "27x27-Brett" }, @@ -1272,6 +1276,7 @@ }, "calculus": { "#board": { + "name": "Standardbrett", "description": "Ungefähr 12 Steine breit" }, "width-10": { @@ -2614,6 +2619,14 @@ "name": "Hexagonales Brett (Basis 8)" } }, + "mirador": { + "#board": { + "name": "28x28-Brett" + }, + "size-40": { + "name": "40x40-Brett" + } + }, "mixtour": { "five": { "description": "Gewinner ist, wer zuerst drei Punkte erzielt.", @@ -4862,6 +4875,9 @@ "STEPS": "Beweglichkeit", "MATERIAL": "Material" }, + "lielow": { + "MOVESUNTILSUICIDE": "Züge bis zum Selbstmord" + }, "majorities": "Punktestände (─, ⟋, ⟍)", "meg": { "OFFENSE": "Angreifender Spieler", diff --git a/locales/en/apgames.json b/locales/en/apgames.json index 8bf62709..872f4ba6 100644 --- a/locales/en/apgames.json +++ b/locales/en/apgames.json @@ -156,7 +156,7 @@ "mimic": "A game where enemy pieces mimic your moves while you race to be the first player to reach the back row.", "minefield": "Connect opposite sides of the board, but certain piece configurations are forbidden.", "minimize": "The player with the largest smallest group wins the game.", - "mirador": "Mirador is a fast and exhilarating connection game played on a 27 x 27 square grid by placing 2 x 2 squares to represent watchtowers. It uses line-of-sight connections and equivalent goals (making it more of a race than a pure connection game).", + "mirador": "Mirador is a fast and exhilarating connection game played on a square grid (28 x 28 by default) by placing 2 x 2 squares to represent watchtowers. It uses line-of-sight connections and equivalent goals (making it more of a race than a pure connection game).", "mixtour": "Two players create towers with the goal of creating a tower at least five high with your colour at the top. The twist here is two-fold: (1) you can move opponent's pieces and (2) movement range is determined by the *target* stack height and not the moving stack height.", "monkey": "You start with a single queen, composed of a stack of checkers. When you make noncapturing moves, the queen leaves a singleton behind. Queens and singletons move and capture like chess queens. To win, capture the opposing queen or leave them with no legal moves.", "morphos": "Orthogonal-only square connection game. On your turn, place a friendly stone or flip an enemy stone in one of three predetermined patterns. Win by connecting your two opposite sides of the board with a chain of stones of your color.", @@ -617,6 +617,7 @@ "konane": "Several competing opening protocols exist, but the most common ruleset is the Naihe Ruleset, used by tournaments at the Bishop Museum in Hawaii and described in the BGG reference. This is what is implemented here.", "knightline": "For convenience, your stack is split approximately in half on your first click. Subsequent clicks on the source or target stack move one piece at a time. When done, click on an empty cell or use the Complete Move button.\n\nThe coordinate system is adapted from the coder's coordinate system for Hive, a game on an unbounded (but still reasonably sized) hex board. The y axis is labeled with Cartesian coordinates (positive and negative integers). The x axis is labeled with letters in alphabetical order, with the origin at (m, 0). If motion on the x-axis exceeds the confines of the alphabet in either direction, the letters are prefixed with another letter (z is followed by aa, ab, ac, etc., and a is preceded by zz, zy, zx, etc.). The game is not expected to reach a width that requires more double coordinates, but for the record, az is followed by ba, za is preceded by yz, and so forth. The board cannot reach a size that would result in ambiguity.", "lasca": "Maneuverability is a measure of how close your pieces are to promoting. Your maximum maneuverability is the board size times the number of stacks you control.\n\nMaterial is calculated by giving you a point for every friendly piece in a stack you control, plus an extra point if you have an officer on top of that stack.", + "lielow": "\"Moves until suicide\" totals for each player how many moves each of their stacks could still make — growing by one each move and always choosing the direction that survives longest — before being forced to bear off. It ignores every other stack on the board, friendly or enemy, so it's a rough measure of how exposed a player's pieces are, not a count of actual legal moves remaining.", "linage": "Linage is a 2016 game designed by Luis Bolaños Mures. The game is based on the following definitions: A **region** is a maximal set of orthogonally contiguous empty points. A **line** is a set of N orthogonally contiguous empty points on the same row or column (default is N=3); and a region is **owned** by Vertical if it contains no horizontal lines, and by Horizontal if it contains no vertical lines. A region is free if it is owned by neither player. Regions must always have at least one line.\n\nOn his turn, the player passes or places a stone in a free region. The game ends when both players pass in succession, and wins the one with highest score (i.e., the number of points in the regions the player owns, plus komi).", "loa": "In the centre of the 9x9 board is a \"black hole.\". Landing on the black hole means the piece is removed from the game. Simultaneous connections are scored as a draw.", "magnate": "The terminology of some Magnate actions has been altered for clarity and brevity. Completely developing a new property is called the \"Buy\" action; purchasing a deed for a new property is called \"Deed\", developing deeds (that is, adding tokens to a deeded property, whether it results in the deed becoming fully developed or not) is called \"Add\". (Selling a card and trading suit tokens 3 for 1 are unchanged.)\n\nIn order to speed up the process of rolling for resources, there are two additional actions:\n* \"Prefer\" is for setting your preference of which suit token to take when a deed pays out on your opponent's roll. If you do not set an explicit preference, the code will choose the rarer token for you based on your non-crown suits and current supply of tokens. The currently preferred token is circled in the UI, but your personal preference is never visible to the other player.\n* \"Choose\" is a mandatory first action for collecting suit tokens when a deed pays out on your own roll. (In all cases where you need to choose a suit token that is not already among your tokens, you still click on the appropriate token pile.)\n\nBecause you can perform several actions during a ply in any order, there is also an \"Undo\" action to back out your most recent action, whether or not it was complete.\n\nNote that only the final resource die result is displayed, but the distribution of expected outcomes is still that of rolling 2d10 and taking the higher value. Taxation happens when the lower of 2d10 comes up 1; a suit die is rolled (or two, in the double taxation variant), and the suits will be displayed underneath the resource result. The roll is logged at the end of a player's turn, and is attributed to the next player (who would have rolled in the physical game). Except for a \"Choose\", no user action is required; resources are added or removed automatically by the server in between turns.\n\nWhen a player is ahead in a district, the Pawn or Excuse for that district is outlined in that player's color. The first tiebreaker score (total property value) is displayed in parentheses after the district score. The second tiebreaker is total number of tokens remaining.", @@ -968,6 +969,9 @@ "board-19": { "name": "19x19 board" }, + "board-23": { + "name": "23x23 board" + }, "board-27": { "name": "27x27 board" }, @@ -1272,6 +1276,7 @@ }, "calculus": { "#board": { + "name": "Default board", "description": "Roughly 12 pieces across" }, "width-10": { @@ -2614,6 +2619,14 @@ "name": "Hexagonal board (base-8)" } }, + "mirador": { + "#board": { + "name": "28x28 board" + }, + "size-40": { + "name": "40x40 board" + } + }, "mixtour": { "five": { "description": "The winner is the first to score three points.", @@ -4862,6 +4875,9 @@ "STEPS": "Maneuverability", "MATERIAL": "Material" }, + "lielow": { + "MOVESUNTILSUICIDE": "Moves until suicide" + }, "majorities": "Scores (─, ⟋, ⟍)", "meg": { "OFFENSE": "Offensive player", diff --git a/locales/eo/apgames.json b/locales/eo/apgames.json index 6cbd5a87..15e4df81 100644 --- a/locales/eo/apgames.json +++ b/locales/eo/apgames.json @@ -656,6 +656,9 @@ "board-19": { "name": "Tabulo 19×19" }, + "board-23": { + "name": "Tabulo 23×23" + }, "board-27": { "name": "Tabulo 27×27" }, @@ -2056,6 +2059,14 @@ "name": "Sesangula tabulo (bazo 8)" } }, + "mirador": { + "#board": { + "name": "Tabulo 28×28" + }, + "size-40": { + "name": "Tabulo 40×40" + } + }, "mixtour": { "five": { "description": "La gajninto estas la unua, kiu gajnas tri poentojn.", @@ -4481,7 +4492,7 @@ "mimic": "Imitanto (angle Mimic): Ludo, en kiu malamikaj pecoj imitas viajn movojn dum vi konkuras por esti la unua, kiu atingas la malantaŭan vicon.", "minefield": "Minkampo (angle Minefield): Konektu kontraŭajn flankojn de la tabulo, sed iuj pecaranĝoj estas malpermesitaj.", "minimize": "Minimumigo (angle Minimize): Gajnas la ludanto, kies plej malgranda grupo estas la plej granda.", - "mirador": "Mirador estas rapida kaj ekscita konektludo sur kvadrata krado 27×27, kie kvadratoj 2×2 reprezentas gardoturojn. Ĝi uzas vidliniajn konektojn kaj ekvivalentajn celojn, do ĝi estas pli vetkuro ol pura konektludo.", + "mirador": "Mirador estas rapida kaj ekscita konektludo sur kvadrata krado (defaŭlte 28×28), kie kvadratoj 2×2 reprezentas gardoturojn. Ĝi uzas vidliniajn konektojn kaj ekvivalentajn celojn, do ĝi estas pli vetkuro ol pura konektludo.", "mixtour": "Du ludantoj konstruas turojn kun la celo fari turon almenaŭ kvin pecojn altan, kun sia koloro supre. Estas du apartaĵoj: (1) vi povas movi kontraŭulajn pecojn, kaj (2) la movdistanco dependas de la alto de la cela stako, ne de tiu de la movata stako.", "monkey": "Simia Damo (angle Monkey Queen): Vi komencas kun unu damo, kiu estas stako de dampecoj. Dum senkapta movo, la damo postlasas unuopan pecon. Damoj kaj unuopaj pecoj moviĝas kaj kaptas kiel ŝakaj damoj. Por venki, kaptu la kontraŭulan damon aŭ lasu la kontraŭulon sen validaj movoj.", "morphos": "Nur-orta kvadrata konektludo. Dum via vico, metu amikan ŝtonon aŭ renversu malamikan ŝtonon laŭ unu el tri antaŭdifinitaj ŝablonoj. Gajnu konektante viajn du kontraŭajn flankojn per ĉeno de samkoloraj ŝtonoj.", diff --git a/locales/es-US/apgames.json b/locales/es-US/apgames.json index 68423dff..681a0b41 100644 --- a/locales/es-US/apgames.json +++ b/locales/es-US/apgames.json @@ -156,7 +156,7 @@ "mimic": "Un juego donde las piezas enemigas imitan tus movimientos mientras compites por ser el primer jugador en llegar a la última fila.", "minefield": "Conecta lados opuestos del tablero, pero ciertas configuraciones de piezas están prohibidas.", "minimize": "El jugador cuyo grupo más pequeño sea el más grande gana el juego.", - "mirador": "Mirador es un juego de conexión rápido y emocionante que se juega en una cuadrícula de 27 x 27 colocando cuadrados de 2 x 2 para representar torres de vigilancia. Utiliza conexiones por línea de visión y objetivos equivalentes (lo que lo convierte más en una carrera que en un juego de conexión puro).", + "mirador": "Mirador es un juego de conexión rápido y emocionante que se juega en una cuadrícula cuadrada (de 28 x 28 por defecto) colocando cuadrados de 2 x 2 para representar torres de vigilancia. Usa conexiones por línea de visión y objetivos equivalentes (lo que lo convierte más en una carrera que en un juego de conexión puro).", "mixtour": "Dos jugadores crean torres con el objetivo de formar una torre de al menos cinco niveles de altura con su color en la parte superior. El giro aquí es doble: (1) puedes mover piezas del oponente y (2) el alcance de movimiento está determinado por la altura de la pila *de destino* y no por la altura de la pila que se mueve.", "monkey": "Empiezas con una sola reina, compuesta por una pila de fichas de damas. Cuando haces movimientos que no capturan, la reina deja una ficha individual detrás. Las reinas y las fichas individuales se mueven y capturan como reinas de ajedrez. Para ganar, captura a la reina opuesta o déjala sin movimientos legales.", "morphos": "Juego de conexión en cuadrícula únicamente ortogonal. En tu turno, coloca una ficha aliada o voltea una ficha enemiga según uno de tres patrones predeterminados. Gana conectando tus dos lados opuestos del tablero con una cadena de fichas de tu color.", @@ -617,6 +617,7 @@ "konane": "Existen varios protocolos de apertura en competencia, pero el reglamento más común es el Reglamento Naihe, utilizado en torneos en el Museo Bishop en Hawái y descrito en la referencia de BGG. Esto es lo que se implementa aquí.", "knightline": "Para mayor comodidad, tu pila se divide aproximadamente a la mitad en tu primer clic. Los clics posteriores en la pila de origen o destino mueven una pieza a la vez. Cuando termines, haz clic en una casilla vacía o usa el botón Completar movimiento.\n\nEl sistema de coordenadas está adaptado del sistema de coordenadas del programador para Hive, un juego en un tablero hexagonal sin límites (pero de tamaño razonable). El eje y está etiquetado con coordenadas cartesianas (enteros positivos y negativos). El eje x está etiquetado con letras en orden alfabético, con el origen en (m, 0). Si el movimiento en el eje x excede los confines del alfabeto en cualquier dirección, las letras se anteponen con otra letra (a la z le sigue aa, ab, ac, etc., y a la a le antecede zz, zy, zx, etc.). No se espera que el juego alcance un ancho que requiera más coordenadas dobles, pero para que conste, a az le sigue ba, a za le antecede yz, y así sucesivamente. El tablero no puede alcanzar un tamaño que provoque ambigüedad.", "lasca": "La maniobrabilidad es una medida de qué tan cerca están tus piezas de coronarse. Tu maniobrabilidad máxima es el tamaño del tablero multiplicado por el número de pilas que controlas.\n\nEl material se calcula dándote un punto por cada pieza propia en una pila que controlas, más un punto extra si tienes un oficial en la parte superior de esa pila.", + "lielow": "\"Movimientos hasta el suicidio\" calcula para cada jugador cuántos movimientos podría realizar aún cada una de sus pilas —creciendo en uno con cada movimiento y eligiendo siempre la dirección que sobreviva más tiempo— antes de verse obligada a retirar piezas. Ignora todas las demás pilas del tablero, ya sean propias o enemigas, por lo que es una medida aproximada de qué tan expuestas están las piezas de un jugador, y no un conteo de los movimientos legales restantes.", "linage": "Linage es un juego de 2016 diseñado por Luis Bolaños Mures. El juego se basa en las siguientes definiciones: Una **región** es un conjunto máximo de puntos vacíos contiguos ortogonalmente. Una **línea** es un conjunto de N puntos vacíos contiguos ortogonalmente en la misma fila o columna (por defecto N=3); y una región es **propiedad** de Vertical si no contiene líneas horizontales, y de Horizontal si no contiene líneas verticales. Una región es libre si no pertenece a ningún jugador. Las regiones siempre deben tener al menos una línea.\n\nEn su turno, el jugador pasa o coloca una piedra en una región libre. El juego termina cuando ambos jugadores pasan sucesivamente, y gana quien tenga la puntuación más alta (es decir, el número de puntos en las regiones que posee el jugador, más el komi).", "loa": "En el centro del tablero de 9x9 hay un \"agujero negro\". Caer en el agujero negro significa que la pieza se elimina del juego. Las conexiones simultáneas se puntúan como un empate.", "magnate": "La terminología de algunas acciones de Magnate se ha modificado para mayor claridad y brevedad. Desarrollar por completo una nueva propiedad se llama la acción \"Comprar\"; adquirir una escritura para una nueva propiedad se llama \"Escriturar\", desarrollar escrituras (es decir, agregar fichas a una propiedad escriturada, resulte o no en que la escritura se desarrolle por completo) se llama \"Agregar\". (Vender una carta y cambiar fichas de palo 3 por 1 permanecen sin cambios).\n\nCon el fin de acelerar el proceso de lanzar por recursos, hay dos acciones adicionales:\n* \"Preferir\" es para establecer tu preferencia sobre qué ficha de palo tomar cuando una escritura paga en el lanzamiento de tu oponente. Si no defines una preferencia explícita, el código elegirá la ficha más rara según tus palos sin corona y tu reserva actual de fichas. La ficha preferida actualmente está rodeada con un círculo en la UI, pero tu preferencia personal nunca es visible para el otro jugador.\n* \"Elegir\" es una primera acción obligatoria para recolectar fichas de palo cuando una escritura paga en tu propio lanzamiento. (En todos los casos en los que necesites elegir una ficha de palo que aún no esté entre tus fichas, sigues haciendo clic en la pila de fichas correspondiente).\n\nDado que puedes realizar varias acciones durante un turno en cualquier orden, también hay una acción de \"Deshacer\" para revertir tu acción más reciente, independientemente de si se completó o no.\n\nTen en cuenta que solo se muestra el resultado final del dado de recursos, pero la distribución de los resultados esperados sigue siendo la de lanzar 2d10 y tomar el valor más alto. La tributación ocurre cuando el menor de los 2d10 resulta en 1; se lanza un dado de palo (o dos, en la variante de doble tributación), y los palos se mostrarán debajo del resultado de recursos. El lanzamiento se registra al final del turno de un jugador y se atribuye al siguiente jugador (quien habría lanzado en el juego físico). Salvo por un \"Elegir\", no se requiere ninguna acción del usuario; los recursos son añadidos o removidos automáticamente por el servidor entre turnos.\n\nCuando un jugador va a la cabeza en un distrito, el Peón o la Excusa para ese distrito se delinea con el color de ese jugador. La primera puntuación de desempate (valor total de la propiedad) se muestra entre paréntesis después de la puntuación del distrito. El segundo desempate es el número total de fichas restantes.", @@ -968,6 +969,9 @@ "board-19": { "name": "Tablero de 19x19" }, + "board-23": { + "name": "Tablero de 23x23" + }, "board-27": { "name": "Tablero de 27x27" }, @@ -1272,6 +1276,7 @@ }, "calculus": { "#board": { + "name": "Tablero predeterminado", "description": "Aproximadamente 12 piezas de ancho" }, "width-10": { @@ -2614,6 +2619,14 @@ "name": "Tablero hexagonal (base 8)" } }, + "mirador": { + "#board": { + "name": "Tablero de 28x28" + }, + "size-40": { + "name": "Tablero de 40x40" + } + }, "mixtour": { "five": { "description": "El ganador es el primero en anotar tres puntos.", @@ -4862,6 +4875,9 @@ "STEPS": "Maniobrabilidad", "MATERIAL": "Material" }, + "lielow": { + "MOVESUNTILSUICIDE": "Movimientos hasta el suicidio" + }, "majorities": "Puntuación (─, ⟋, ⟍)", "meg": { "OFFENSE": "Jugador atacante", diff --git a/locales/fr/apgames.json b/locales/fr/apgames.json index 9bab325a..578dcfab 100644 --- a/locales/fr/apgames.json +++ b/locales/fr/apgames.json @@ -156,7 +156,7 @@ "mimic": "Un jeu où les pièces ennemies imitent vos déplacements pendant que vous faites la course pour être le premier joueur à atteindre la dernière rangée.", "minefield": "Reliez les côtés opposés du plateau, mais certaines configurations de pièces sont interdites.", "minimize": "Le joueur ayant le plus grand groupe le plus petit gagne la partie.", - "mirador": "Mirador est un jeu de connexion rapide et palpitant joué sur une grille carrée de 27 x 27 en plaçant des carrés de 2 x 2 pour représenter des tours de guet. Il utilise des connexions par ligne de vue et des objectifs équivalents (ce qui en fait plus une course qu'un pur jeu de connexion).", + "mirador": "Mirador est un jeu de connexion rapide et captivant qui se joue sur une grille carrée (28 x 28 par défaut) en plaçant des carrés de 2 x 2 représentant des tours de guet. Il utilise des connexions en ligne de mire et des objectifs équivalents (ce qui en fait davantage une course qu'un pur jeu de connexion).", "mixtour": "Deux joueurs créent des tours dans le but de former une tour d'au moins cinq étages avec leur couleur au sommet. Le rebondissement est double : (1) vous pouvez déplacer les pièces adverses et (2) la portée de déplacement est déterminée par la hauteur de la pile *cible* et non par celle de la pile qui se déplace.", "monkey": "Vous commencez avec une seule reine, composée d'une pile de dames. Lorsque vous effectuez des déplacements sans capture, la reine laisse un pion isolé derrière elle. Les reines et les pions isolés se déplacent et capturent comme des dames d'échecs. Pour gagner, capturez la reine adverse ou laissez votre adversaire sans coup légal.", "morphos": "Jeu de connexion sur grille carrée uniquement orthogonale. À votre tour, placez une pierre amie ou retournez une pierre ennemie selon l'un des trois motifs prédéterminés. Gagnez en reliant vos deux côtés opposés du plateau avec une chaîne de pierres de votre couleur.", @@ -617,6 +617,7 @@ "konane": "Plusieurs protocoles d'ouverture existent, mais le jeu de règles le plus courant est le Naihe Ruleset, utilisé lors des tournois au Bishop Museum d'Hawaï et décrit dans la référence BGG. C'est ce qui est implémenté ici.", "knightline": "Pour votre commodité, votre pile est séparée environ en deux lors de votre premier clic. Les clics ultérieurs sur la pile source ou cible déplacent une pièce à la fois. Lorsque vous avez terminé, cliquez sur une case vide ou utilisez le bouton Valider le coup.\n\nLe système de coordonnées est adapté du système de coordonnées du développeur pour Hive, un jeu sur un plateau hexagonal non borné (mais de taille raisonnable). L'axe y est étiqueté avec des coordonnées cartésiennes (entiers positifs et négatifs). L'axe x est étiqueté avec des lettres par ordre alphabétique, avec l'origine en (m, 0). Si le déplacement sur l'axe x dépasse les limites de l'alphabet dans un sens ou dans l'autre, les lettres sont précédées d'une autre lettre (z est suivi de aa, ab, ac, etc., et a est précédé de zz, zy, zx, etc.). Il n'est pas prévu que le jeu atteigne une largeur nécessitant plus de doubles coordonnées, mais pour mémoire, az est suivi de ba, za est précédé de yz, et ainsi de suite. Le plateau ne peut pas atteindre une taille qui entraînerait une ambiguïté.", "lasca": "La manœuvrabilité mesure à quel point vos pièces sont proches de la promotion. Votre manœuvrabilité maximale est égale à la taille du plateau multipliée par le nombre de piles que vous contrôlez.\n\nLe matériel est calculé en vous accordant un point pour chaque pièce alliée dans une pile que vous contrôlez, plus un point supplémentaire si vous avez un officier au sommet de cette pile.", + "lielow": "\"Coups avant suicide\" totalise pour chaque joueur le nombre de coups que chacune de ses piles pourrait encore effectuer — augmentant d'un à chaque coup et choisissant toujours la direction qui survit le plus longtemps — avant d'être contrainte de sortir du plateau. Cet indicateur ignore toutes les autres piles sur le plateau, alliées comme ennemies ; c'est donc une mesure approximative de l'exposition des pièces d'un joueur, et non un décompte des coups légaux réellement restants.", "linage": "Linage est un jeu de 2016 conçu par Luis Bolaños Mures. Le jeu repose sur les définitions suivantes : Une **région** est un ensemble maximal de points vides contigus de manière orthogonale. Une **ligne** est un ensemble de N points vides contigus de manière orthogonale sur la même rangée ou colonne (par défaut N=3) ; et une région est **possédée** par Vertical si elle ne contient aucune ligne horizontale, et par Horizontal si elle ne contient aucune ligne verticale. Une région est libre si elle n'appartient à aucun des deux joueurs. Les régions doivent toujours contenir au moins une ligne.\n\nÀ son tour, le joueur passe ou place une pierre dans une région libre. La partie se termine lorsque les deux joueurs passent consécutivement, et le joueur avec le score le plus élevé l'emporte (c'est-à-dire le nombre de points dans les régions que le joueur possède, plus le komi).", "loa": "Au centre du plateau 9x9 se trouve un « trou noir ». S'arrêter sur le trou noir entraîne le retrait de la pièce du jeu. Des connexions simultanées se soldent par une partie nulle.", "magnate": "La terminologie de certaines actions de Magnate a été modifiée par souci de clarté et de concision. Développer complètement une nouvelle propriété est appelé l'action « Buy » ; acheter un titre de propriété pour une nouvelle propriété est appelé « Deed », développer des titres de propriété (c'est-à-dire ajouter des jetons à une propriété sous titre, que cela entraîne un développement complet ou non) est appelé « Add ». (Vendre une carte et échanger des jetons de couleur à 3 contre 1 restent inchangés.)\n\nAfin d'accélérer le processus de lancer pour les ressources, il existe deux actions supplémentaires :\n* « Prefer » sert à définir votre préférence sur le jeton de couleur à prendre lorsqu'un titre rapporte sur le lancer de votre adversaire. Si vous ne définissez pas de préférence explicite, le code choisira pour vous le jeton le plus rare en fonction de vos couleurs non-couronne et de votre réserve actuelle de jetons. Le jeton actuellement préféré est entouré dans l'interface, mais votre préférence personnelle n'est jamais visible par l'autre joueur.\n* « Choose » est une première action obligatoire pour collecter des jetons de couleur lorsqu'un titre rapporte sur votre propre lancer. (Dans tous les cas où vous devez choisir un jeton de couleur qui ne figure pas encore parmi vos jetons, vous cliquez toujours sur la pile de jetons appropriée.)\n\nComme vous pouvez effectuer plusieurs actions au cours d'un tour dans n'importe quel ordre, il existe également une action « Undo » pour annuler votre action la plus récente, qu'elle ait été terminée ou non.\n\nNotez que seul le résultat final du dé de ressources est affiché, mais la distribution des résultats attendus reste celle d'un lancer de 2d10 en retenant la valeur la plus élevée. La taxation a lieu lorsque le plus faible des 2d10 donne 1 ; un dé de couleur est lancé (ou deux, dans la variante de double taxation), et les couleurs seront affichées sous le résultat de la ressource. Le lancer est enregistré à la fin du tour d'un joueur, et est attribué au joueur suivant (qui aurait lancé dans le jeu physique). À l'exception d'un « Choose », aucune action de l'utilisateur n'est requise ; les ressources sont ajoutées ou retirées automatiquement par le serveur entre les tours.\n\nLorsqu'un joueur est en tête dans un quartier, le Pion ou l'Excuse de ce quartier est entouré de la couleur de ce joueur. Le premier score de départage (valeur totale de la propriété) est affiché entre parenthèses après le score du quartier. Le deuxième critère de départage est le nombre total de jetons restants.", @@ -968,6 +969,9 @@ "board-19": { "name": "Plateau 19x19" }, + "board-23": { + "name": "Plateau 23x23" + }, "board-27": { "name": "Plateau 27x27" }, @@ -1272,6 +1276,7 @@ }, "calculus": { "#board": { + "name": "Plateau par défaut", "description": "Environ 12 pièces de largeur" }, "width-10": { @@ -2614,6 +2619,14 @@ "name": "Plateau hexagonal (base 8)" } }, + "mirador": { + "#board": { + "name": "Plateau 28x28" + }, + "size-40": { + "name": "Plateau 40x40" + } + }, "mixtour": { "five": { "description": "Le gagnant est le premier à marquer trois points.", @@ -4862,6 +4875,9 @@ "STEPS": "Maniabilité", "MATERIAL": "Matériel" }, + "lielow": { + "MOVESUNTILSUICIDE": "Coups avant suicide" + }, "majorities": "Scores (─, ⟋, ⟍)", "meg": { "OFFENSE": "Joueur offensif", diff --git a/locales/it/apgames.json b/locales/it/apgames.json index 790f565f..219ce0e3 100644 --- a/locales/it/apgames.json +++ b/locales/it/apgames.json @@ -156,7 +156,7 @@ "mimic": "Un gioco in cui i pezzi nemici imitano le tue mosse mentre fai a gara per essere il primo giocatore a raggiungere l'ultima riga.", "minefield": "Collega i lati opposti del tabellone, ma alcune configurazioni di pezzi sono proibite.", "minimize": "Il giocatore con il gruppo più piccolo più grande vince la partita.", - "mirador": "Mirador è un gioco di connessione veloce ed esaltante giocato su una griglia quadrata 27 x 27 posizionando quadrati 2 x 2 per rappresentare torri di guardia. Utilizza connessioni in linea di vista ed obiettivi equivalenti (rendendolo più una corsa che un puro gioco di connessione).", + "mirador": "Mirador è un gioco di connessione rapido ed entusiasmante giocato su una griglia quadrata (28 x 28 come impostazione predefinita) piazzando quadrati 2 x 2 per rappresentare torri di guardia. Utilizza connessioni in linea di vista e obiettivi equivalenti (rendendolo più una corsa che un puro gioco di connessione).", "mixtour": "Due giocatori creano torri con l'obiettivo di formarne una alta almeno cinque elementi con il proprio colore in cima. Il risvolto qui è duplice: (1) puoi muovere i pezzi dell'avversario e (2) il raggio di movimento è determinato dall'altezza della pila di *destinazione* e non dall'altezza della pila che si muove.", "monkey": "Inizi con una singola regina, composta da una pila di dame. Quando fai mosse senza cattura, la regina lascia indietro un singolo pezzo. Le regine e i pezzi singoli si muovono e catturano come le donne negli scacchi. Per vincere, cattura la regina avversaria o lasciala senza mosse legali.", "morphos": "Gioco di connessione su griglia quadrata solo ortogonale. Nel tuo turno, posiziona una pietra alleata o ribalta una pietra nemica in uno dei tre schemi predeterminati. Vinci collegando i due lati opposti del tabellone con una catena di pietre del tuo colore.", @@ -617,6 +617,7 @@ "konane": "Esistono diversi protocolli di apertura in concorrenza tra loro, ma il regolamento più comune è il regolamento Naihe, utilizzato nei tornei presso il Bishop Museum alle Hawaii e descritto nel riferimento su BGG. Questo è ciò che è implementato qui.", "knightline": "Per comodità, la tua pila viene divisa approssimativamente a metà al tuo primo clic. I clic successivi sulla pila di origine o di destinazione muovono un pezzo alla volta. Al termine, fai clic su una casella vuota o usa il pulsante Completa Mossa.\n\nIl sistema di coordinate è adattato dal sistema di coordinate dello sviluppatore per Hive, un gioco su un tabellone esagonale illimitato (ma comunque di dimensioni ragionevoli). L'asse y è etichettato con coordinate cartesiane (interi positivi e negativi). L'asse x è etichettato con lettere in ordine alfabetico, con l'origine in (m, 0). Se il movimento sull'asse x supera i confini dell'alfabeto in una delle due direzioni, le lettere vengono precedute da un'altra lettera (z è seguita da aa, ab, ac, ecc., e a è preceduta da zz, zy, zx, ecc.). Non si prevede che il gioco raggiunga una larghezza tale da richiedere ulteriori doppie coordinate, ma per la cronaca, az è seguita da ba, za è preceduta da yz e così via. Il tabellone non può raggiungere dimensioni tali da generare ambiguità.", "lasca": "La manovrabilità è una misura di quanto i tuoi pezzi siano vicini alla promozione. La tua manovrabilità massima è pari alla dimensione del tabellone moltiplicata per il numero di pile che controlli.\n\nIl materiale viene calcolato assegnandoti un punto per ogni pezzo amico in una pila che controlli, più un punto extra se hai un ufficiale in cima a quella pila.", + "lielow": "\"Mosse fino al suicidio\" calcola per ciascun giocatore quante mosse ciascuna delle sue pile potrebbe ancora compiere — crescendo di uno a ogni mossa e scegliendo sempre la direzione che sopravvive più a lungo — prima di essere costretta a uscire dal tabellone. Ignora ogni altra pila sul tabellone, amica o nemica, quindi è una misura approssimativa di quanto siano esposte le pedine di un giocatore, non un conteggio delle mosse legali effettivamente rimaste.", "linage": "Linage è un gioco del 2016 progettato da Luis Bolaños Mures. Il gioco si basa sulle seguenti definizioni: una **regione** è un insieme massimale di punti vuoti ortogonalmente contigui. Una **linea** è un insieme di N punti vuoti ortogonalmente contigui sulla stessa riga o colonna (il valore predefinito è N=3); e una regione è di **proprietà** di Verticale se non contiene linee orizzontali, e di Orizzontale se non contiene linee verticali. Una regione è libera se non appartiene a nessuno dei due giocatori. Le regioni devono sempre contenere almeno una linea.\n\nNel proprio turno, il giocatore passa o posiziona una pedina in una regione libera. La partita termina quando entrambi i giocatori passano consecutivamente, e vince chi ha il punteggio più alto (ovvero il numero di punti nelle regioni possedute dal giocatore, più il komi).", "loa": "Al centro del tabellone 9x9 c'è un \"buco nero\". Atterrare sul buco nero comporta la rimozione del pezzo dal gioco. Le connessioni simultanee sono considerate una patta.", "magnate": "La terminologia di alcune azioni di Magnate è stata modificata per chiarezza e brevità. Lo sviluppo completo di una nuova proprietà è chiamato azione \"Acquista\" (Buy); l'acquisto del titolo di proprietà per una nuova proprietà è chiamato \"Atto\" (Deed); lo sviluppo dei titoli (ovvero l'aggiunta di segnalini a una proprietà con atto, indipendentemente dal fatto che renda l'atto completamente sviluppato o meno) è chiamato \"Aggiungi\" (Add). (La vendita di una carta e lo scambio di 3 a 1 dei segnalini seme rimangono invariati.)\n\nPer velocizzare il processo di lancio dei dadi per le risorse, ci sono due azioni aggiuntive:\n* \"Preferisci\" serve a impostare la preferenza su quale segnalino seme prendere quando un atto paga sul lancio dell'avversario. Se non imposti una preferenza esplicita, il codice sceglierà per te il segnalino più raro in base ai tuoi semi non-corona e alla tua riserva attuale di segnalini. Il segnalino attualmente preferito è cerchiato nell'interfaccia, ma la tua preferenza personale non è mai visibile all'altro giocatore.\n* \"Scegli\" è un'azione iniziale obbligatoria per raccogliere i segnalini seme quando un atto paga sul tuo stesso lancio. (In tutti i casi in cui devi scegliere un segnalino seme non ancora presente tra i tuoi segnalini, fai comunque clic sulla pila di segnalini appropriata.)\n\nPoiché puoi eseguire diverse azioni durante una semimossa in qualsiasi ordine, c'è anche un'azione \"Annulla\" per annullare l'azione più recente, indipendentemente dal fatto che fosse completa o meno.\n\nNota che viene visualizzato solo il risultato finale del dado risorsa, ma la distribuzione dei risultati attesi è comunque quella di un lancio di 2d10 prendendo il valore più alto. La tassazione avviene quando il valore più basso di 2d10 è 1; viene lanciato un dado seme (o due, nella variante a doppia tassazione) e i semi verranno mostrati sotto il risultato della risorsa. Il lancio viene registrato alla fine del turno di un giocatore ed è attribuito al giocatore successivo (che avrebbe lanciato il dado nel gioco fisico). A eccezione di \"Scegli\", non è richiesta alcuna azione dell'utente; le risorse vengono aggiunte o rimosse automaticamente dal server tra un turno e l'altro.\n\nQuando un giocatore è in vantaggio in un distretto, la Pedina o la Scusa per quel distretto è contornata con il colore di quel giocatore. Il primo punteggio di spareggio (valore totale della proprietà) è mostrato tra parentesi dopo il punteggio del distretto. Il secondo criterio di spareggio è il numero totale di segnalini rimanenti.", @@ -968,6 +969,9 @@ "board-19": { "name": "Tavoliere 19x19" }, + "board-23": { + "name": "Plancia 23x23" + }, "board-27": { "name": "Tavoliere 27x27" }, @@ -1272,6 +1276,7 @@ }, "calculus": { "#board": { + "name": "Scacchiera predefinita", "description": "Circa 12 pezzi di larghezza" }, "width-10": { @@ -2614,6 +2619,14 @@ "name": "Tabellone esagonale (base 8)" } }, + "mirador": { + "#board": { + "name": "Plancia 28x28" + }, + "size-40": { + "name": "Plancia 40x40" + } + }, "mixtour": { "five": { "description": "Vince chi ottiene per primo tre punti.", @@ -4862,6 +4875,9 @@ "STEPS": "Manovrabilità", "MATERIAL": "Materiale" }, + "lielow": { + "MOVESUNTILSUICIDE": "Mosse fino al suicidio" + }, "majorities": "Punteggi (─, ⟋, ⟍)", "meg": { "OFFENSE": "Giocatore in attacco", diff --git a/src/games/asli.ts b/src/games/asli.ts index 2be77258..bdf95b39 100644 --- a/src/games/asli.ts +++ b/src/games/asli.ts @@ -60,6 +60,7 @@ export class AsliGame extends GameBase { {uid: "board-15", group: "board"}, {uid: "board-17", group: "board"}, {uid: "board-19", group: "board"}, + {uid: "board-23", group: "board"}, {uid: "board-27", group: "board"}, {uid: "woven", group: "rules"}, {uid: "setkomi", group: "komi"}, diff --git a/src/games/bridges.ts b/src/games/bridges.ts index 9aba6b3e..e617eeb3 100644 --- a/src/games/bridges.ts +++ b/src/games/bridges.ts @@ -383,7 +383,6 @@ export class BridgesGame extends GameBase { const bridgeOptions = this.bridgeCompletions(m, legalMoves); if (bridgeOptions.length === 1) { result.valid = true; - result.complete = -1; result.autocomplete = bridgeOptions[0]; return result; } @@ -412,7 +411,6 @@ export class BridgesGame extends GameBase { const matches = legalMoves.filter(mv => mv.startsWith(m)); if (matches.length === 1 && matches[0] !== m) { result.valid = true; - result.complete = -1; result.autocomplete = matches[0]; return result; } @@ -427,8 +425,8 @@ export class BridgesGame extends GameBase { } result.valid = true; - result.complete = (this.stack.length === 1 || m === "pass" || m.includes(",")) ? 1 : -1; - if (result.complete === -1) { + result.complete = (this.stack.length === 1 || m === "pass" || m.includes(",")) ? 1 : 0; + if (result.complete === 0) { result.message = i18next.t("apgames:validation.bridges.ONE_MORE"); } else { result.message = i18next.t("apgames:validation._general.VALID_MOVE"); diff --git a/src/games/catsdogs.ts b/src/games/catsdogs.ts index 726c217a..6ab801e0 100644 --- a/src/games/catsdogs.ts +++ b/src/games/catsdogs.ts @@ -52,7 +52,7 @@ export class CatsDogsGame extends GameBase { ], categories: ["goal>immobilize", "mechanic>move", "board>shape>rect", "components>simple>1per"], variants: [ - { uid: "#board", }, // Huntoon's variant + { uid: "#ruleset", }, // Huntoon's variant { uid: "original", group: "ruleset" }, { uid: "tournament", group: "ruleset" }, // 8x8 Portuguese tournament rules { uid: "misere", group: "ruleset" }, // misÈre version of original 8x8 diff --git a/src/games/lielow.ts b/src/games/lielow.ts index eb625762..76a780a1 100644 --- a/src/games/lielow.ts +++ b/src/games/lielow.ts @@ -24,6 +24,196 @@ export interface ILielowState extends IAPGameState { stack: Array; }; +// Number of moves a lone stack at [row][col] can make—growing by one each move, +// choosing direction each time to survive as long as possible—before it has no +// choice left but to bear off. Indexed as [stackHeight - 1][row][col]. Ignores +// interference from other stacks, friendly or enemy. +const stackMovesToSuicideEight: number[][][] = [ + [ // 1-stacks + [8, 8, 8, 8, 8, 8, 8, 8], + [8, 8, 8, 8, 8, 8, 8, 8], + [8, 8, 8, 8, 8, 8, 8, 8], + [8, 8, 8, 8, 8, 8, 8, 8], + [8, 8, 8, 8, 8, 8, 8, 8], + [8, 8, 8, 8, 8, 8, 8, 8], + [8, 8, 8, 8, 8, 8, 8, 8], + [8, 8, 8, 8, 8, 8, 8, 8], + ], + [ // 2-stacks + [7, 7, 7, 7, 7, 7, 7, 7], + [7, 7, 7, 7, 7, 7, 7, 7], + [7, 7, 7, 7, 7, 7, 7, 7], + [7, 7, 7, 7, 7, 7, 7, 7], + [7, 7, 7, 7, 7, 7, 7, 7], + [7, 7, 7, 7, 7, 7, 7, 7], + [7, 7, 7, 7, 7, 7, 7, 7], + [7, 7, 7, 7, 7, 7, 7, 7], + ], + [ // 3-stacks + [5, 6, 6, 6, 6, 6, 6, 5], + [6, 6, 6, 6, 6, 6, 6, 6], + [6, 6, 6, 6, 6, 6, 6, 6], + [6, 6, 6, 6, 6, 6, 6, 6], + [6, 6, 6, 6, 6, 6, 6, 6], + [6, 6, 6, 6, 6, 6, 6, 6], + [6, 6, 6, 6, 6, 6, 6, 6], + [5, 6, 6, 6, 6, 6, 6, 5], + ], + [ // 4-stacks + [3, 5, 5, 4, 4, 5, 5, 3], + [5, 5, 5, 5, 5, 5, 5, 5], + [5, 5, 5, 5, 5, 5, 5, 5], + [4, 5, 5, 4, 4, 5, 5, 4], + [4, 5, 5, 4, 4, 5, 5, 4], + [5, 5, 5, 5, 5, 5, 5, 5], + [5, 5, 5, 5, 5, 5, 5, 5], + [3, 5, 5, 4, 4, 5, 5, 3], + ], + [ // 5-stacks + [3, 4, 4, 2, 2, 4, 4, 3], + [4, 4, 4, 4, 4, 4, 4, 4], + [4, 4, 4, 3, 3, 4, 4, 4], + [2, 4, 3, 1, 1, 3, 4, 2], + [2, 4, 3, 1, 1, 3, 4, 2], + [4, 4, 4, 3, 3, 4, 4, 4], + [4, 4, 4, 4, 4, 4, 4, 4], + [3, 4, 4, 2, 2, 4, 4, 3], + ], + [ // 6-stacks + [3, 3, 2, 2, 2, 2, 3, 3], + [3, 3, 3, 3, 3, 3, 3, 3], + [2, 3, 1, 1, 1, 1, 3, 2], + [2, 3, 1, 1, 1, 1, 3, 2], + [2, 3, 1, 1, 1, 1, 3, 2], + [2, 3, 1, 1, 1, 1, 3, 2], + [3, 3, 3, 3, 3, 3, 3, 3], + [3, 3, 2, 2, 2, 2, 3, 3], + ], + [ // 7-stacks + [2, 2, 2, 2, 2, 2, 2, 2], + [2, 1, 1, 1, 1, 1, 1, 2], + [2, 1, 1, 1, 1, 1, 1, 2], + [2, 1, 1, 1, 1, 1, 1, 2], + [2, 1, 1, 1, 1, 1, 1, 2], + [2, 1, 1, 1, 1, 1, 1, 2], + [2, 1, 1, 1, 1, 1, 1, 2], + [2, 2, 2, 2, 2, 2, 2, 2], + ], + [ // 8-stacks + [1, 1, 1, 1, 1, 1, 1, 1], + [1, 1, 1, 1, 1, 1, 1, 1], + [1, 1, 1, 1, 1, 1, 1, 1], + [1, 1, 1, 1, 1, 1, 1, 1], + [1, 1, 1, 1, 1, 1, 1, 1], + [1, 1, 1, 1, 1, 1, 1, 1], + [1, 1, 1, 1, 1, 1, 1, 1], + [1, 1, 1, 1, 1, 1, 1, 1], + ] +]; + +// Same as `stackMovesToSuicideEight`, but for the 9x9 board (the `size-9` variant). +const stackMovesToSuicideNine: number[][][] = [ + [ // 1-stacks + [9, 9, 9, 9, 9, 9, 9, 9, 9], + [9, 9, 9, 9, 9, 9, 9, 9, 9], + [9, 9, 9, 9, 9, 9, 9, 9, 9], + [9, 9, 9, 9, 9, 9, 9, 9, 9], + [9, 9, 9, 9, 9, 9, 9, 9, 9], + [9, 9, 9, 9, 9, 9, 9, 9, 9], + [9, 9, 9, 9, 9, 9, 9, 9, 9], + [9, 9, 9, 9, 9, 9, 9, 9, 9], + [9, 9, 9, 9, 9, 9, 9, 9, 9], + ], + [ // 2-stacks + [8, 8, 8, 8, 8, 8, 8, 8, 8], + [8, 8, 8, 8, 8, 8, 8, 8, 8], + [8, 8, 8, 8, 8, 8, 8, 8, 8], + [8, 8, 8, 8, 8, 8, 8, 8, 8], + [8, 8, 8, 8, 8, 8, 8, 8, 8], + [8, 8, 8, 8, 8, 8, 8, 8, 8], + [8, 8, 8, 8, 8, 8, 8, 8, 8], + [8, 8, 8, 8, 8, 8, 8, 8, 8], + [8, 8, 8, 8, 8, 8, 8, 8, 8], + ], + [ // 3-stacks + [7, 7, 7, 7, 7, 7, 7, 7, 7], + [7, 7, 7, 7, 7, 7, 7, 7, 7], + [7, 7, 7, 7, 7, 7, 7, 7, 7], + [7, 7, 7, 7, 7, 7, 7, 7, 7], + [7, 7, 7, 7, 7, 7, 7, 7, 7], + [7, 7, 7, 7, 7, 7, 7, 7, 7], + [7, 7, 7, 7, 7, 7, 7, 7, 7], + [7, 7, 7, 7, 7, 7, 7, 7, 7], + [7, 7, 7, 7, 7, 7, 7, 7, 7], + ], + [ // 4-stacks + [3, 5, 6, 6, 4, 6, 6, 5, 3], + [5, 6, 6, 6, 6, 6, 6, 6, 5], + [6, 6, 6, 6, 6, 6, 6, 6, 6], + [6, 6, 6, 6, 6, 6, 6, 6, 6], + [4, 6, 6, 6, 4, 6, 6, 6, 4], + [6, 6, 6, 6, 6, 6, 6, 6, 6], + [6, 6, 6, 6, 6, 6, 6, 6, 6], + [5, 6, 6, 6, 6, 6, 6, 6, 5], + [3, 5, 6, 6, 4, 6, 6, 5, 3], + ], + [ // 5-stacks + [3, 5, 5, 4, 2, 4, 5, 5, 3], + [5, 5, 5, 5, 4, 5, 5, 5, 5], + [5, 5, 5, 5, 5, 5, 5, 5, 5], + [4, 5, 5, 4, 3, 4, 5, 5, 4], + [2, 4, 5, 3, 1, 3, 5, 4, 2], + [4, 5, 5, 4, 3, 4, 5, 5, 4], + [5, 5, 5, 5, 5, 5, 5, 5, 5], + [5, 5, 5, 5, 4, 5, 5, 5, 5], + [3, 5, 5, 4, 2, 4, 5, 5, 3], + ], + [ // 6-stacks + [3, 4, 4, 2, 2, 2, 4, 4, 3], + [4, 4, 4, 4, 4, 4, 4, 4, 4], + [4, 4, 4, 3, 3, 3, 4, 4, 4], + [2, 4, 3, 1, 1, 1, 3, 4, 2], + [2, 4, 3, 1, 1, 1, 3, 4, 2], + [2, 4, 3, 1, 1, 1, 3, 4, 2], + [4, 4, 4, 3, 3, 3, 4, 4, 4], + [4, 4, 4, 4, 4, 4, 4, 4, 4], + [3, 4, 4, 2, 2, 2, 4, 4, 3], + ], + [ // 7-stacks + [3, 3, 2, 2, 2, 2, 2, 3, 3], + [3, 3, 3, 3, 3, 3, 3, 3, 3], + [2, 3, 1, 1, 1, 1, 1, 3, 2], + [2, 3, 1, 1, 1, 1, 1, 3, 2], + [2, 3, 1, 1, 1, 1, 1, 3, 2], + [2, 3, 1, 1, 1, 1, 1, 3, 2], + [2, 3, 1, 1, 1, 1, 1, 3, 2], + [3, 3, 3, 3, 3, 3, 3, 3, 3], + [3, 3, 2, 2, 2, 2, 2, 3, 3], + ], + [ // 8-stacks + [2, 2, 2, 2, 2, 2, 2, 2, 2], + [2, 1, 1, 1, 1, 1, 1, 1, 2], + [2, 1, 1, 1, 1, 1, 1, 1, 2], + [2, 1, 1, 1, 1, 1, 1, 1, 2], + [2, 1, 1, 1, 1, 1, 1, 1, 2], + [2, 1, 1, 1, 1, 1, 1, 1, 2], + [2, 1, 1, 1, 1, 1, 1, 1, 2], + [2, 1, 1, 1, 1, 1, 1, 1, 2], + [2, 2, 2, 2, 2, 2, 2, 2, 2], + ], + [ // 9-stacks + [1, 1, 1, 1, 1, 1, 1, 1, 1], + [1, 1, 1, 1, 1, 1, 1, 1, 1], + [1, 1, 1, 1, 1, 1, 1, 1, 1], + [1, 1, 1, 1, 1, 1, 1, 1, 1], + [1, 1, 1, 1, 1, 1, 1, 1, 1], + [1, 1, 1, 1, 1, 1, 1, 1, 1], + [1, 1, 1, 1, 1, 1, 1, 1, 1], + [1, 1, 1, 1, 1, 1, 1, 1, 1], + [1, 1, 1, 1, 1, 1, 1, 1, 1], + ] +]; + export class LielowGame extends GameBase { public static readonly gameinfo: APGamesInformation = { name: "Lielow", @@ -33,6 +223,8 @@ export class LielowGame extends GameBase { dateAdded: "2023-12-24", // i18next.t("apgames:descriptions.lielow") description: "apgames:descriptions.lielow", + // i18next.t("apgames:notes.lielow") + notes: "apgames:notes.lielow", urls: ["https://boardgamegeek.com/boardgame/349408/lielow"], bggid: "349408", people: [ @@ -677,9 +869,28 @@ export class LielowGame extends GameBase { return [...this.board.values()].filter(v => v[0] === player).map(v => v[1]).length; } + // For each player, the sum, over all of their stacks, of the number of moves + // that stack could make (ignoring interference from other stacks) before being + // forced to bear off. Returns [player1Total, player2Total]. + private movesUntilSuicide(): number[] { + const movesUntilSuicide: number[] = [0, 0]; + this.board.forEach((cell, coord) => { + const [x, y] = this.algebraic2coords(coord); + const [player, stackHeight] = cell; + if (this.boardSize === 8) { + movesUntilSuicide[player - 1] += stackMovesToSuicideEight[stackHeight - 1][y][x]; + } else if (this.boardSize === 9) { + movesUntilSuicide[player - 1] += stackMovesToSuicideNine[stackHeight - 1][y][x]; + } + }); + return movesUntilSuicide; + } + public sidebarScores(): IScores[] { + const suicideMoves = this.movesUntilSuicide(); return [ - { name: this.neutralAreaLabel("apgames:status.PIECESREMAINING"), scores: [this.getPlayerPieces(1), this.getPlayerPieces(2)] } + { name: this.neutralAreaLabel("apgames:status.PIECESREMAINING"), scores: [this.getPlayerPieces(1), this.getPlayerPieces(2)] }, + { name: this.neutralAreaLabel("apgames:status.lielow.MOVESUNTILSUICIDE"), scores: [suicideMoves[0], suicideMoves[1]] } ] } diff --git a/src/games/mirador.ts b/src/games/mirador.ts index e1465437..0b96e2f3 100644 --- a/src/games/mirador.ts +++ b/src/games/mirador.ts @@ -9,7 +9,7 @@ import { import type { APGamesInformation } from "../schemas/gameinfo.js"; import { APRenderRep, AnnotationBasic } from "@abstractplay/renderer/build/schemas/schema"; import type { APMoveResult } from "../schemas/moveresults.js"; -import { reviver, UserFacingError } from "../common/index.js"; +import { generateColumnLabel, reviver, UserFacingError } from "../common/index.js"; import i18next from "i18next"; export type playerid = 1 | 2; @@ -18,8 +18,8 @@ export type Stage = "play" | "challenge"; export interface IMoveState extends IIndividualState { currplayer: playerid; - // board is 27 x 27. A1 corresponds to board[0][0], board[0][1], board[1][0], and board[1][1], - // Z26 corresponds to board[25][25], board[25][26], board[26][25], board[26][26] + // The stored grid is one row and column smaller than the rendered board. + // A placement at (x, y) occupies a 2x2 block from board[y][x] through board[y + 1][x + 1]. board: Array>; stage: Stage; lastmove?: string; @@ -56,6 +56,15 @@ export class MiradorGame extends GameBase { apid: "a96b36a2-2c9d-4597-8c4a-f926062a45b6", }, ], + variants: [ + { + uid: "#board", + }, + { + uid: "size-40", + group: "board", + }, + ], categories: ["goal>connect", "mechanic>block", "mechanic>place", "board>shape>rect", "board>connect>rect", "components>simple>pnp"], flags: ["pie", "custom-buttons"], }; @@ -70,13 +79,34 @@ export class MiradorGame extends GameBase { public stack!: Array; public results: Array = []; - constructor(state?: IMiradorState | string) { + private static readonly defaultBoardSize = 28; + + private get boardSize(): number { + const sizeVariant = this.variants.find((variant) => /^size-\d+$/.test(variant)); + if (sizeVariant === undefined) { + return MiradorGame.defaultBoardSize; + } + return Number.parseInt(sizeVariant.slice("size-".length), 10); + } + + private get gridSize(): number { + return this.boardSize - 1; + } + + private get placementSize(): number { + return this.boardSize - 2; + } + + constructor(state?: IMiradorState | string, variants?: string[]) { super(); if (state === undefined) { + if (variants !== undefined) { + this.variants = [...variants]; + } const board = []; - for (let row = 0; row < 27; row++) { + for (let row = 0; row < this.gridSize; row++) { const node: Array = []; - for (let col = 0; col < 27; col++) { + for (let col = 0; col < this.gridSize; col++) { node.push(null); } board.push(node); @@ -132,10 +162,10 @@ export class MiradorGame extends GameBase { } const moves: string[] = []; // placements - for (let x = 0; x < 26; x++) { - for (let y = 0; y < 26; y++) { + for (let x = 0; x < this.placementSize; x++) { + for (let y = 0; y < this.placementSize; y++) { if (this.canPlace(this.board, this.currplayer, x, y)) { - moves.push(GameBase.coords2algebraic(x, y, 26)); + moves.push(GameBase.coords2algebraic(x, y, this.placementSize)); } } } @@ -159,18 +189,18 @@ export class MiradorGame extends GameBase { piece?: string ): IClickResult { try { - if (col === 0 || col === 27 || row === 0 || row === 27) { + if (col === 0 || col === this.boardSize - 1 || row === 0 || row === this.boardSize - 1) { return { move, valid: false, message: i18next.t("apgames:validation.mirador.NO_EDGE_PLAY") }; } - const cell = GameBase.coords2algebraic(col - 1, row - 1, 26); + const cell = GameBase.coords2algebraic(col - 1, row - 1, this.placementSize); const newmove = move ? `${move}-${cell}` : cell; const result = this.validateMove(newmove) as IClickResult; if (!result.valid) { - result.move = ""; + result.move = move; } else { result.move = newmove; } @@ -194,10 +224,10 @@ export class MiradorGame extends GameBase { const localBoard = []; const work: [number, number][] = []; if (horizontal) { - for (let row = 0; row < 27; row++) { + for (let row = 0; row < this.gridSize; row++) { const node: Array = []; let seeleft = true; - for (let col = 0; col < 27; col++) { + for (let col = 0; col < this.gridSize; col++) { if (seeleft && this.board[row][col] === player) { node.push(3); // 3 means connected to the left work.push([row, col]); @@ -212,10 +242,10 @@ export class MiradorGame extends GameBase { localBoard.push(node); } } else { - for (let col = 0; col < 27; col++) { + for (let col = 0; col < this.gridSize; col++) { const node: Array = []; let seeleft = true; - for (let row = 0; row < 27; row++) { + for (let row = 0; row < this.gridSize; row++) { if (seeleft && this.board[row][col] === player) { node.push(3); work.push([col, row]); // transposing the board @@ -242,10 +272,10 @@ export class MiradorGame extends GameBase { let dist = 1; while (true) { const next: [number, number] = [start[0] + dir[0] * dist, start[1] + dir[1] * dist]; - if (next[1] >= 27) { + if (next[1] >= this.gridSize) { return true; } - if (next[0] < 0 || next[0] >= 27 || next[1] < 0 || localBoard[next[0]][next[1]] === 3 - player || localBoard[next[0]][next[1]] === 3) { + if (next[0] < 0 || next[0] >= this.gridSize || next[1] < 0 || localBoard[next[0]][next[1]] === 3 - player || localBoard[next[0]][next[1]] === 3) { break; } if (localBoard[next[0]][next[1]] === 3 - player) { @@ -267,7 +297,7 @@ export class MiradorGame extends GameBase { ]; for (const dir of diags) { const next: [number, number] = [start[0] + dir[0], start[1] + dir[1]]; - if (! (next[0] < 0 || next[0] >= 27 || next[1] < 0 || next[1] >= 27) && localBoard[next[0]][next[1]] === player) { + if (! (next[0] < 0 || next[0] >= this.gridSize || next[1] < 0 || next[1] >= this.gridSize) && localBoard[next[0]][next[1]] === player) { localBoard[next[0]][next[1]] = 3; work.push(next); } @@ -279,7 +309,7 @@ export class MiradorGame extends GameBase { private canPlace(board: Array>, player: playerid, x: number, y: number): boolean { for (let dx = -1; dx <= 2; dx++) { for (let dy = -1; dy <= 2; dy++) { - if (x + dx >= 0 && x + dx < 27 && y + dy >= 0 && y + dy < 27 && !(board[y + dy][x + dx] === null || ((dx === -1 || dx === 2) && (dy === -1 || dy === 2) && board[y + dy][x + dx] === player))) { + if (x + dx >= 0 && x + dx < this.gridSize && y + dy >= 0 && y + dy < this.gridSize && !(board[y + dy][x + dx] === null || ((dx === -1 || dx === 2) && (dy === -1 || dy === 2) && board[y + dy][x + dx] === player))) { return false; } } @@ -339,7 +369,7 @@ export class MiradorGame extends GameBase { for (const placement of placements) { let coords; try { - coords = GameBase.algebraic2coords(placement, 26); + coords = GameBase.algebraic2coords(placement, this.placementSize); } catch { result.valid = false; result.message = i18next.t("apgames:validation._general.INVALIDCELL", { @@ -347,7 +377,7 @@ export class MiradorGame extends GameBase { }); return result; } - if (coords[0] < 0 || coords[0] >= 26 || coords[1] < 0 || coords[1] >= 26) { + if (coords[0] < 0 || coords[0] >= this.placementSize || coords[1] < 0 || coords[1] >= this.placementSize) { result.valid = false; result.message = i18next.t("apgames:validation._general.INVALIDCELL", { cell: placement, @@ -363,7 +393,7 @@ export class MiradorGame extends GameBase { localBoard[coords[1]][coords[0]] = this.currplayer; localBoard[coords[1]][coords[0] + 1] = this.currplayer; localBoard[coords[1] + 1][coords[0]] = this.currplayer; - localBoard[coords[1] + 1][coords[0]] = this.currplayer; + localBoard[coords[1] + 1][coords[0] + 1] = this.currplayer; } else { if (!this.canPlace(this.board, this.currplayer, coords[0], coords[1])) { result.valid = false; @@ -418,7 +448,7 @@ export class MiradorGame extends GameBase { } else { const placements = m.split("-"); for (const placement of placements) { - const coords = GameBase.algebraic2coords(placement, 26); + const coords = GameBase.algebraic2coords(placement, this.placementSize); this.board[coords[1]][coords[0]] = this.currplayer; this.board[coords[1]][coords[0] + 1] = this.currplayer; this.board[coords[1] + 1][coords[0]] = this.currplayer; @@ -489,11 +519,12 @@ export class MiradorGame extends GameBase { public render(): APRenderRep { // Build piece string - let pstr = "----------------------------"; - for (let row = 0; row < 26; row++) { + const border = "-".repeat(this.boardSize); + let pstr = border; + for (let row = 0; row < this.placementSize; row++) { pstr += "\n"; const pieces: string[] = []; - for (let col = 0; col < 26; col++) { + for (let col = 0; col < this.placementSize; col++) { if (this.board[row][col] !== null && this.board[row][col] === this.board[row][col + 1] && this.board[row][col] === this.board[row + 1][col] && this.board[row][col] === this.board[row + 1][col + 1]) { pieces.push(this.board[row][col] === 1 ? "A" : "B"); } else { @@ -502,17 +533,27 @@ export class MiradorGame extends GameBase { } pstr += "-" + pieces.join("") + "-"; } - pstr += "\n----------------------------"; + pstr += `\n${border}`; + + const labelIterator = generateColumnLabel("abcdefghijklmnopqrstuvwxyz"); + const columnLabels = Array.from( + { length: this.placementSize }, + () => labelIterator.next().value as string, + ); + const rowLabels = Array.from( + { length: this.placementSize }, + (_, index) => (index + 1).toString(), + ); // Build rep const rep: APRenderRep = { options: ["hide-star-points"], board: { style: "vertex", - width: 28, - height: 28, - columnLabels: ["", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", ""], - rowLabels: ["", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "25", "26", ""] + width: this.boardSize, + height: this.boardSize, + columnLabels: ["", ...columnLabels, ""], + rowLabels: ["", ...rowLabels, ""], }, legend: { A: { @@ -535,7 +576,7 @@ export class MiradorGame extends GameBase { for (const move of this.results) { if (move.type === "place") { for (const placement of move.where!.split("-")) { - const [x, y] = GameBase.algebraic2coords(placement, 26); + const [x, y] = GameBase.algebraic2coords(placement, this.placementSize); rep.annotations.push({type: "dots", targets: [{row: y + 1, col: x + 1}], size: 0.3, colour: "#f4ea56"}); } } diff --git a/test/games/asli.test.ts b/test/games/asli.test.ts new file mode 100644 index 00000000..6b5ad9f8 --- /dev/null +++ b/test/games/asli.test.ts @@ -0,0 +1,23 @@ +import "mocha"; +import { expect } from "chai"; +import { AsliGame } from "../../src/games/asli"; + +describe("Asli", () => { + it("includes the 23x23 board size in the variant metadata", () => { + expect(AsliGame.gameinfo.variants).to.deep.include({ uid: "board-23", group: "board" }); + }); + + it("uses a 23x23 board when the board-23 variant is selected", () => { + const game = new AsliGame(undefined, ["board-23"]); + const rep = game.render(); + + expect(game.boardsize).to.equal(23); + expect(rep.board).to.include({ width: 23, height: 23 }); + expect(game.getGraph().graph.order).to.equal(23 * 23); + expect(game.coords2algebraic(22, 0)).to.equal("w23"); + + const restored = new AsliGame(game.serialize()); + expect(restored.variants).to.deep.equal(["board-23"]); + expect(restored.boardsize).to.equal(23); + }); +}); diff --git a/test/games/mirador.test.ts b/test/games/mirador.test.ts new file mode 100644 index 00000000..43faf302 --- /dev/null +++ b/test/games/mirador.test.ts @@ -0,0 +1,117 @@ +import "mocha"; +import { expect } from "chai"; +import { MiradorGame } from "../../src/games/mirador"; + +describe("Mirador", () => { + it("names both board sizes in the variant metadata", () => { + expect(MiradorGame.gameinfo.variants).to.deep.equal([ + { uid: "#board" }, + { uid: "size-40", group: "board" }, + ]); + }); + + it("keeps the standard 28x28 board as the default", () => { + const game = new MiradorGame(); + const rep = game.render(); + + expect(game.board).to.have.length(27); + expect(Object.keys(game.board[0])).to.have.length(27); + expect(rep.board).to.include({ width: 28, height: 28 }); + expect(game.moves()).to.have.length(26 * 26 + 1); + expect(game.moves()).to.include.members(["a26", "z1", "declare"]); + }); + + it("supports legal placements and multi-letter notation on the 40x40 board", () => { + const game = new MiradorGame(undefined, ["size-40"]); + const rep = game.render(); + const board = rep.board as { columnLabels: string[]; height: number; rowLabels: string[]; width: number }; + + expect(game.board).to.have.length(39); + expect(Object.keys(game.board[0])).to.have.length(39); + expect(board).to.include({ width: 40, height: 40 }); + expect(board.columnLabels).to.have.length(40); + expect(board.columnLabels.slice(-3)).to.deep.equal(["ak", "al", ""]); + expect(board.rowLabels).to.have.length(40); + expect(board.rowLabels.slice(-3)).to.deep.equal(["37", "38", ""]); + + const moves = game.moves(); + expect(moves).to.have.length(38 * 38 + 1); + expect(moves).to.include.members(["a38", "z38", "aa38", "al1", "declare"]); + expect(game.validateMove("aa38").valid).to.equal(true); + expect(game.validateMove("al1").valid).to.equal(true); + expect(game.validateMove("am1").valid).to.equal(false); + expect(game.validateMove("al0").valid).to.equal(false); + + const click = game.handleClick("", 1, 27); + expect(click.valid).to.equal(true); + expect(click.move).to.equal("aa38"); + expect(game.handleClick("", 1, 39).valid).to.equal(false); + + game.move("al1"); + expect(game.board[37][37]).to.equal(1); + expect(game.board[37][38]).to.equal(1); + expect(game.board[38][37]).to.equal(1); + expect(game.board[38][38]).to.equal(1); + + const restored = new MiradorGame(game.serialize()); + expect(restored.variants).to.deep.equal(["size-40"]); + expect(restored.render().board).to.include({ width: 40, height: 40 }); + }); + + it("accepts multi-letter placements during a challenge", () => { + const game = new MiradorGame(undefined, ["size-40"]); + game.move("declare"); + + const validation = game.validateMove("aa38-al1"); + expect(validation.valid).to.equal(true); + expect(validation.complete).to.equal(0); + }); + + it("rejects adjacent placements within the same challenge response", () => { + const game = new MiradorGame(undefined, ["size-40"]); + game.move("declare"); + + expect(game.validateMove("a38-c37").valid).to.equal(false); + }); + + it("preserves earlier challenge placements after rejecting orthogonal adjacency", () => { + for (const variants of [[], ["size-40"]]) { + const game = new MiradorGame(undefined, variants); + game.move("declare"); + + const first = game.handleClick("", 1, 1); + expect(first.valid).to.equal(true); + + const illegal = game.handleClick(first.move, 2, 3); + expect(illegal.valid).to.equal(false); + expect(illegal.move).to.equal(first.move); + } + }); + + it("preserves earlier challenge placements after rejecting diagonal contact with an opponent", () => { + for (const variants of [[], ["size-40"]]) { + const game = new MiradorGame(undefined, variants); + game.board[0][0] = 1; + game.board[0][1] = 1; + game.board[1][0] = 1; + game.board[1][1] = 1; + game.move("declare"); + + const first = game.handleClick("", 5, 5); + expect(first.valid).to.equal(true); + + const illegal = game.handleClick(first.move, 3, 3); + expect(illegal.valid).to.equal(false); + expect(illegal.move).to.equal(first.move); + } + }); + + it("checks connections against the enlarged board edge", () => { + const game = new MiradorGame(undefined, ["size-40"]); + game.board[0][0] = 1; + game.board[0][25] = 1; + game.board[0][30] = 2; + + expect(game["isConnected"](true, 1)).to.equal(false); + }); +});