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
20 changes: 20 additions & 0 deletions locales/en/apgames.json
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,7 @@
"valley": "Get your king to the center space, but your pieces must always move as far as they can. Teamwork is essential.",
"veletas": "Drawless territory game where players control a number of neutral shooters and shoot stones of their own colour from them. In order to win, a player must claim a majority of neutral pieces by having them surrounded by larger groups of their own pieces than their opponent's.",
"verge": "Verge is a game where players attempt to create groups that partition the board, freezing those groups and removing enemy groups. The first player to have no legal placement wins.",
"viruswar": "Paper and pencil game about growing and destroying viruses.",
"volcano": "An Icehouse puzzle game for 2 players. Stacks of pyramids are volcanos, some of which are capped. As you move caps around, you cause eruptions that may lead to you capturing pieces. The winner is the first to capture a certain number of trios.",
"volo": "Volo was inspired by the beauty of birds flying in flocks. Each player in turn places a piece or moves one or more pieces (here called 'birds') on the board and attempts to connect them all in one contiguous 'flock.' If a player ends up with one contiguous flock (of any size), he wins.",
"waldmeister": "Players take turns planting trees in an attempt to create groups of either colours or heights. Highest score after two rounds wins.",
Expand Down Expand Up @@ -339,6 +340,7 @@
"twinflames": "Twin Flames is a 2026 redesign of the 2013's Product, an original concept by Nick Bentley. The first player must initially place a friendly stone, preventing overly strong opening countermoves and thereby eliminating the need for a pie rule. The remaining moves use a 12* sequence, in which players may place stones of either colour. At the end of the game, a player who has formed a single connected group scores points equal to the size of that group. Another ludeme introduced was the use of walls, or blockers, which reduce overall connectivity and make groups more robust to enemy attacks. The blocker configuration is randomized, increasing game variability and making opening theory more difficult to develop.",
"twixt": "The notation is based on Hansel notation at <http://www.ibiblio.org/twixtpuzzles/>. Some modifications are that link removal specifically specifies the link direction, and commas separate the moves. To add/remove links, click on the pegs between them. You can also remove a link by clicking on the line itself.",
"unane": "Ūnane, designed by Mark Steere in 2026, is an unification game inspired by the ancient Hawiian game of Kōnane. True to the spirit of Kōnane, Ūnane begins with a checkerboard pattern of stones, has short-range captures, and is extremely simple. \"Ūnane\" is a fusion of Una (Spanish for \"one\") and Kōnane. This is intended as a tribute to Kōnane, not cultural appropriation.\n\nŪnane has common ground with Kōnane, especially in both players are mainly trying to isolate and remove their own stones.",
"viruswar": "Virus War (aka, Клоподавка, Bug Supression) is a pencil and paper game played in Russia around the 1970s/80s. The players have `N` multiple moves per turn (`N` depends on the board size). Each player has a home base on opposite corners. On his turn, a player plays N squares on the grid. Plays can be on empty squares (making a new virus), or by replacing an adversary virus with a defensive wall. A wall becomes unplayable. However, players can only play on squares that are adjacent to the group of friendly pieces that includes the player's home base. A stalemated player loses the game.",
"waldmeister": "Players play two games sequentially. In the first round, Player 1 is playing for colours and Player 2 is playing for heights. At the end of the first round, scores are tabulated and scoring groups highlighted. Then in the second round, Player 2 plays first and plays for colours, and Player 1 plays for heights.",
"witch": "The first player does not start as owning any pieces and may remove any piece (other than a crown) on their first turn. The second player chooses their colour on their first turn, after which, removing your opponent's pieces is no longer possible.",
"xana": "Players, on their turns, drop/move a stack (there's a limited amount of stackable pieces) and optionally drop two walls into empty hexes. Stacks without liberties are captured. A stack has liberty if at least one of the adjacent hexes is empty (there is no concept of group of stacks). A hex is accessible if it is empty and connected to a friendly stack by a path of empty hexes. The goal is to build the highest score of territory plus captures. Xana was designed in 2005.",
Expand Down Expand Up @@ -3400,6 +3402,20 @@
"name": "Size-7 board (127 cells)"
}
},
"viruswar": {
"size-10": {
"name": "10x10 board (3 moves)"
},
"size-20": {
"name": "20x20 board (4 moves)"
},
"size-25": {
"name": "25x25 board (5 moves)"
},
"#board": {
"name": "30x30 board (6 moves)"
}
},
"volo": {
"#board": {
"name": "Size-7 board"
Expand Down Expand Up @@ -6750,6 +6766,10 @@
"FROZEN_NEIGHBOUR": "You cannot place next one of your frozen groups.",
"INITIAL_INSTRUCTIONS": "Select an empty cell that is not adjacent to one of your frozen groups."
},
"viruswar": {
"INITIAL_INSTRUCTIONS": "Place {{count}} pieces, each must be adjacent to the group of friendly pieces including your home-base. Pieces can be active viruses (circles), or defensive walls (squares). Either place a virus on an empty cell, or replace an enemy virus with a friendly defensive wall.",
"CANNOT_GROW": "Square {{where}} cannot receive a new virus/wall!"
},
"volcano": {
"BAD_FROM": "{{from}} doesn't look like a position on the board, or a piece in your stash.",
"INITIAL_INSTRUCTIONS": "Select a cap to move or a piece from your captured pile to place on the board.",
Expand Down
1 change: 1 addition & 0 deletions locales/en/apresults.json
Original file line number Diff line number Diff line change
Expand Up @@ -497,6 +497,7 @@
"worker": "{{player}} placed an architect at {{where}}."
},
"veletas": "{{player}} placed a {{what}} at {{where}}.",
"viruswar": "{{player}} placed viruses/walls at {{where}}.",
"volo": "{{player}} adds a bird at {{where}}."
},
"PLAYSECOND": "{{player}} chose to play second.",
Expand Down
8 changes: 6 additions & 2 deletions src/games/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,7 @@ import { NarrowsGame, INarrowsState } from "./narrows";
import { InvectorGame, IInvectorState } from "./invector";
import { TricouleurGame, ITricouleurState } from "./tricouleur";
import { PositGame, IPositState } from "./posit";
import { VirusWarGame, IVirusWarState } from "./viruswar";

export {
APGamesInformation, GameBase, GameBaseSimultaneous, IAPGameState,
Expand Down Expand Up @@ -523,6 +524,7 @@ export {
InvectorGame, IInvectorState,
TricouleurGame, ITricouleurState,
PositGame, IPositState,
VirusWarGame, IVirusWarState,
};

const games = new Map<string, typeof AmazonsGame | typeof BlamGame | typeof CannonGame |
Expand Down Expand Up @@ -613,7 +615,7 @@ const games = new Map<string, typeof AmazonsGame | typeof BlamGame | typeof Cann
typeof AtariGoGame | typeof TanboGame | typeof UnaneGame |
typeof LinageGame | typeof PolluxGame | typeof PippinzipGame |
typeof NarrowsGame | typeof InvectorGame | typeof TricouleurGame |
typeof PositGame
typeof PositGame | typeof VirusWarGame
>();
// Manually add each game to the following array
[
Expand Down Expand Up @@ -653,7 +655,7 @@ const games = new Map<string, typeof AmazonsGame | typeof BlamGame | typeof Cann
XanaGame, SporaGame, SquirmGame, PinchGame, DomineeringGame, TwinFlamesGame, YGame, ShapeChessGame,
SlimetrailGame, CatsDogsGame, SoccolotGame, CourtGame, HalmaGame, MinimizeGame, HalmaClimbersGame,
SynapseGame, AtariGoGame, TanboGame, UnaneGame, LinageGame, PolluxGame, PippinzipGame, NarrowsGame,
InvectorGame, TricouleurGame, PositGame
InvectorGame, TricouleurGame, PositGame, VirusWarGame
].forEach((g) => {
if (games.has(g.gameinfo.uid)) {
throw new Error("Another game with the UID '" + g.gameinfo.uid + "' has already been used. Duplicates are not allowed.");
Expand Down Expand Up @@ -1185,6 +1187,8 @@ export const GameFactory = (game: string, ...args: any[]): GameBase|GameBaseSimu
return new TricouleurGame(...args);
case "posit":
return new PositGame(...args);
case "viruswar":
return new VirusWarGame(args[0], ...args.slice(1));
}
return;
}
8 changes: 4 additions & 4 deletions src/games/linage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -522,10 +522,10 @@ export class LinageGame extends GameBase {
return []; // no buttons should appear when typing Komi at start
}
if (this.isPieTurn()) {
return [{ label: "play second", move: "play-second" }];
return [{ label: "playsecond", move: "play-second" }];
}
if (this.isButtonActive()) {
return [{ label: "take button", move: "take-button" }];
return [{ label: "takebutton", move: "take-button" }];
}
return [{ label: "pass", move: "pass" }];
}
Expand All @@ -539,9 +539,9 @@ export class LinageGame extends GameBase {
public getPlayerScore(player: number): number {
let komi = this.buttontaker === player ? 0.5 : 0;
if (player === 1 && this.komi !== undefined && this.komi < 0)
komi = -this.komi;
komi += -this.komi;
if (player === 2 && this.komi !== undefined && this.komi > 0)
komi = this.komi;
komi += this.komi;

const terr = this.getTerritories();
return terr.filter(t => t.owner === player).reduce((prev, curr) => prev + curr.cells.length, komi);
Expand Down
Loading
Loading