Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions locales/en/apgames.json
Original file line number Diff line number Diff line change
Expand Up @@ -311,7 +311,7 @@
"stawvs": "For clarity, the game pieces are represented as circles, though in real life, caps (small pyramids of distinct player colors) are usually used. The UI will sort and score your trees (trios consisting of one of each pyramid size) for you as in Mega-Volcano, but for reference the point values are: 7 points for each monochrome tree, 5 points for multicolor trees, and 1 point each for loose pyramids. Except in the variant where final pyramids aren't collected, the pyramids under player pieces are added to the players' collections and scored, but greyed-out pyramids remain on the board under the pieces to clarify the final position.",
"stigmergy": "You control a space if more than half of the lines of sight to it end at a piece of your color. Your score is the sum of the number of pieces of your color on the board and the number of empty spaces you control, plus a komi bonus and a button bonus. The button is used when the komi value plus the number of spaces on the board is even, and any player may take a turn off and claim the button if it has yet to be claimed. The game ends when both players pass in succession, but claiming the button does not count toward this. Players cannot pass until the entire board is occupied or controlled.",
"stiletto": "A dagger represents an option for a double move. Stiletto is a 2003 game from the family of Gomoku, where players try to make a five in-a-row. The main difference is that the second player (traditionally White) starts with a dagger. This allows to compensate for Black's strong initial advantage. When players use the dagger, they pass it to the adversary.\n\nIn terms of 'power' available to players, this variant lies between Gomoku and Connect6. The fact that the power to play two stones in not shared, adds tension to the gameplay.\n\nThe **Open-4** variant makes it illegal to create an open-4 with both dagger stones, which removes part of the dagger's power.\n\n_Stiletto_, from the Italian, is a small, slender dagger with a long, narrow blade designed primarily for thrusting.",
"synapse": "Synapse was first proposed, c.1070, by Pierre Berloquin. This game is played on a 4x4 board with 15 stones of each one of two colors. Each player chooses one to three matches of the same color, and place them in the next square, where the color defines the vertical or horizontal direction. The board could not have more than 25 stones in total. Later in 1976 a variant, by the same author, uses homogenous matches where the matches' heads define the direction. The current implemented version is based on this principle, using Looney Pyramids. This is a larger board with more pieces, proposed in 2005, by Joseph Kisenwether.",
"synapse": "Synapse was first proposed, c.1970, by Pierre Berloquin. This game is played on a 4x4 board with 15 stones of each one of two colors. Each player chooses one to three matches of the same color, and place them in the next square, where the color defines the vertical or horizontal direction. The board could not have more than 25 stones in total. Later in 1976 a variant, by the same author, uses homogenous matches where the matches' heads define the direction. The current implemented version is based on this principle, using Looney Pyramids. This is a larger board with more pieces, proposed in 2005, by Joseph Kisenwether.",
"tablero": "When it's your turn, you will see the dice you have to work with, but once your move is complete, the dice will reroll. Exploration is not helpful because the dice roll is not finalized until after the move is submitted. As you scroll back through the game history, the dice you see are the dice for the *next* turn. The dice used to make the move you're seeing are displayed below the board.\n\nWhile most moves can be unambiguously made by simple clicks, sometimes a button is more helpful. The Place, Take, and Bump buttons to the left of the board are there if you need them.",
"tafl": "The variant names are in the format {ruleset}-{board size}-{initial layout}-{optional: starting player}. For example, 'linnaean-9x9-tcross-w' is the linnaean rules on a 9x9 board with T-cross setup, and the starting player is the defenders. If starting player is not mentioned, then attackers start.",
"taiji": "Moves are done with two clicks. The first tile you place is always the light one, and then the dark one.",
Expand Down Expand Up @@ -2577,6 +2577,9 @@
},
"original": {
"name": "8x8 board (6 men)"
},
"swap": {
"name": "includes swap dribble"
}
},
"spire": {
Expand Down Expand Up @@ -5989,6 +5992,7 @@
"BALL_INSTRUCTIONS": "Now selected an adjacent friendly man to kick the ball in the opposite direction",
"ERROR_KICK_DRIBBLE": "Either (a) select a man to run, or (b) select a man and then select the adjacent ball, or (c) select the ball and then an adjacent man!",
"DRIBBLE_INSTRUCTIONS": "Click an adjacent empty cell from the man, to move both man and ball in that direction (those cells must be both empty). It is also possible for the ball (or man) to move into the man's (or ball's) current position (if the other moves to an empty cell).",
"DRIBBLE_SWAP_INSTRUCTIONS": "Click an adjacent empty cell from the man, to move both man and ball in that direction (those cells must be both empty). It is also possible for the ball (or man) to move into the man's (or ball's) current position (if the other moves to an empty cell), or select the man again to swap the ball with it.",
"KICK_INSTRUCTIONS": "Click an empty cell in the opposite direction of the man, to move the ball. Notice that the ball cannot jump over other pieces."
},
"spire": {
Expand Down Expand Up @@ -6247,7 +6251,7 @@
"TOO_LONG": "You may not add more stones if your first move is to create a new group."
},
"synapse": {
"INITIAL_INSTRUCTIONS": "Place a friendly piece at the required square.",
"INITIAL_INSTRUCTIONS": "Place a friendly piece at the marked square.",
"INVALID_MOVE": "Move {{move}} is invalid!",
"PLACE_INSTRUCTIONS": "Click on the piece until it is the required size, then click on an orthogonal adjacent square to define the direction."
},
Expand Down
42 changes: 35 additions & 7 deletions src/games/soccolot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ export class SoccolotGame extends GameBase {
variants: [
{ uid: "#board", }, // Speed Soccolot
{ uid: "original", group: "ruleset" },
{ uid: "swap", group: "ruleset" }, // adds swap dribble
],
flags: ["experimental"]
};
Expand All @@ -59,7 +60,7 @@ export class SoccolotGame extends GameBase {
public variants: string[] = [];
public stack!: Array<IMoveState>;
public results: Array<APMoveResult> = [];
private ruleset: "default" | "original";
private ruleset: "default" | "original" | "swap";
private _points: [number, number][] = []; // if there are points here, the renderer will show them

constructor(state?: ISoccolotState | string, variants?: string[]) {
Expand Down Expand Up @@ -123,8 +124,9 @@ export class SoccolotGame extends GameBase {
return this;
}

private getRuleset(): "default" | "original" {
private getRuleset(): "default" | "original" | "swap" {
if (this.variants.includes("original")) { return "original"; }
if (this.variants.includes("swap")) { return "swap"; }
return "default";
}

Expand Down Expand Up @@ -211,6 +213,15 @@ export class SoccolotGame extends GameBase {
}
}

if ( this.ruleset === "swap" ) {
for (const man of grid.neighbours(ball)) {
// find adjacent friendly Men
if ( this.board.has(man) && this.board.get(man)! === player ) {
moves.push(`${man},${ball}@`); // swap pieces
}
}
}

return moves.sort((a,b) => a.localeCompare(b));
}

Expand All @@ -234,7 +245,11 @@ export class SoccolotGame extends GameBase {
if ( moves[0] === this.getBall() ) { // it is a kick (final)
newmove = `${move}>${cell}`;
} else { // it is a dribble (final)
newmove = `${move}-${cell}`;
if ( this.ruleset === "swap" && cell === moves[0]) {
newmove = `${move}@`; // swap the ball with the man
} else {
newmove = `${move}-${cell}`; // move the ball with the man
}
}
} else {
newmove = ""; // something went wrong, reset move
Expand Down Expand Up @@ -268,7 +283,7 @@ export class SoccolotGame extends GameBase {
}

const prevplayer = this.currplayer % 2 + 1 as playerid;
const moves: string[] = m.split(/[,>-]/);
const moves: string[] = m.split(/[,>@-]/);

if ( moves.length === 1 ) {
if ( !this.board.has(m) || this.board.get(m)! === prevplayer ) {
Expand Down Expand Up @@ -309,7 +324,11 @@ export class SoccolotGame extends GameBase {
result.complete = -1;
result.canrender = true;
if (this.board.get(moves[0])! === this.currplayer) {
result.message = i18next.t("apgames:validation.soccolot.DRIBBLE_INSTRUCTIONS");
if ( this.ruleset === "swap" ) {
result.message = i18next.t("apgames:validation.soccolot.DRIBBLE_SWAP_INSTRUCTIONS");
} else {
result.message = i18next.t("apgames:validation.soccolot.DRIBBLE_INSTRUCTIONS");
}
} else {
result.message = i18next.t("apgames:validation.soccolot.KICK_INSTRUCTIONS");
}
Expand All @@ -330,7 +349,7 @@ export class SoccolotGame extends GameBase {

// return the list of cells the current move can go to
private findPoints(move: string): string[] {
const moves = move.split(/[,>-]/);
const moves = move.split(/[,>@-]/);
const allMoves = this.moves();
const ball = this.getBall();
const res = [];
Expand All @@ -352,7 +371,11 @@ export class SoccolotGame extends GameBase {
// show available places to dribble (select moves like man,ball-newman)
// or to kick (select moves like ball,man>newball)
res.push(...allMoves.filter(m => m.startsWith(move))
.filter(m => !m.includes('@'))
.map(m => m.split(/[,>-]/)[2]));
if ( this.ruleset === "swap" && moves[1] === ball ) { // include swap option
res.push(moves[0]); // swap by clicking in the man again
}
}

return res;
Expand All @@ -373,7 +396,7 @@ export class SoccolotGame extends GameBase {
}

this.results = [];
const moves = m.split(/[,>-]/);
const moves = m.split(/[,>@-]/);

if ( partial ) { // if partial, set the points to be shown
const g = this.graph;
Expand Down Expand Up @@ -402,6 +425,11 @@ export class SoccolotGame extends GameBase {
this.results.push({ type: "move", from: moves[0], to: moves[2] });
this.board.set(newBall, 3);
this.results.push({ type: "move", from: moves[1], to: newBall });
} else if ( m.includes('@') ) { // only for swap variant
this.board.set(moves[0], 3); // swap ball with man
this.results.push({ type: "move", from: moves[0], to: moves[1] });
this.board.set(moves[1], this.currplayer);
this.results.push({ type: "move", from: moves[1], to: moves[0] });
} else { // a kick (ball,man>newball)
this.board.delete(moves[0]);
this.board.set(moves[2], 3); // moving the ball
Expand Down
4 changes: 2 additions & 2 deletions src/games/synapse.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ export class SynapseGame extends GameBase {
apid: "9228bccd-a1bd-452b-b94f-d05380e6638f",
},
],
categories: ["goal>score>immobilize", "mechanic>place", "board>shape>rect", "components>pyramids"],
categories: ["goal>immobilize", "mechanic>place", "board>shape>rect", "components>pyramids"],
flags: ["player-stashes", "experimental"]
};

Expand Down Expand Up @@ -384,7 +384,7 @@ export class SynapseGame extends GameBase {

const starColour: Colourfuncs = {
func: "custom",
default: "#FFDF00", // gold yellow
default: "#AD03DE", // vibrant purple (alternative: "#FFDF00", // gold yellow)
palette: 3
};

Expand Down
Loading