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
50 changes: 50 additions & 0 deletions locales/en/apgames.json
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@
"irensei": "Irensei is a mixture of Go and Gomoku. Get a seven in a row inside the middle 15x15 region of the Go board to win. To reduce the first player's advantage, the first player loses if they make an overline (even if it extends beyond the 15x15 region), but the second player may win by overline.",
"jacynth": "A Decktet card game where opponents vye for control of the city of Jacynth. Place cards, exert influence, and control the most area to win.",
"kachit": "A chess-like game played on a 4x4 board where you try to eliminate the opposing king or promote your own. Pieces can change their orientation after moving.",
"knightline": "A four-in-a-row connection game played by splitting a stack of knights on an unbounded grid.",
"konane": "A traditional Hawaiian game that was almost completely lost to time but for the memory of a single woman, Kaʻahaʻaina Naihe of Kailua-Kona. Played on a rectangular board, each player captures by jumping over their opponent's pieces. Last to move wins.",
"krypte": "A 4-in-a-row game where pieces enter from active sides that rotate after each turn, and placing a piece flips all adjacent pieces.",
"lasca": "A Draughts variant where captured pieces remain on the board and can be freed later. Immobilize your opponent to win.",
Expand Down Expand Up @@ -309,6 +310,7 @@
"invector": "Invector, designed by Mark Steere in 2026, is an elimination game inspired by the ancient Hawiian game of Kōnane. Invector begins with a checkerboard pattern of stones, has short range captures, and is extremely simple. Invector simply combines two basic, off-the-shelf ingredients: orthogonal, adjacent capturing moves, and orthogonal, adjacent moves closer to center.",
"jacynth": "More information on the Decktet system can be found on the [official Decktet website](https://www.decktet.com). Cards in players' hands are hidden from observers and opponents.",
"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.",
"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.",
Expand Down Expand Up @@ -1838,6 +1840,28 @@
"description": "The board starts with six cards in a circular pattern."
}
},
"knightline": {
"#setup": {
"name": "Default setup",
"description": "No special pieces, and stacks begin in a set configuration."
},
"blocker": {
"name": "Blocker",
"description": "The game begins with a central neutral piece, and stacks are placed by players."
},
"wildcard": {
"name": "Wildcard",
"description": "A central neutral piece may be counted by any player, and stacks are placed by players."
},
"#size": {
"name": "Default stack size",
"description": "All players start with a stack of 20 pieces."
},
"size-24": {
"name": "Stack of 24",
"description": "All players start with a stack of 24 pieces."
}
},
"konane": {
"#board": {
"name": "6x6 board",
Expand Down Expand Up @@ -3927,6 +3951,12 @@
"name": "Hide restriction indicators"
}
},
"knightline": {
"show-origin": {
"description": "Mark the position of the first piece.",
"name": "Show origin"
}
},
"krypte": {
"moves_no_sides_yes": {
"description": "Don't show possible moves.",
Expand Down Expand Up @@ -5692,6 +5722,26 @@
"PARTIAL_destination": "Select a destination.",
"PARTIAL_orientation": "Select a neighbouring cell to orient the piece."
},
"knightline": {
"BAD_PASS": "You may not pass if legal moves are available.",
"BAD_OPENING_MOVE": "The opening move in this variant must be a legal cell for initial stack placement.",
"BAD_START_PLACE": "The cell {{cell}} is not a legal initial placement.",
"BAD_VALUE": "The value {{what}} is not a legal split of your stack.",
"INITIAL_INSTRUCTIONS": "Select a stack, then select a cell to jump to.",
"INITIAL_INSTRUCTIONS_VARIANTS": "Select a cell to place your initial stack.",
"INVALID_FIRST_MOVE": "In the first move of a two-player game, you may only split one piece off your stack.",
"INVALID_MOVE": "You must select a stack with a jump to an unoccupied space.",
"INVALID_NOTATION": "The move notation '{{move}}' is invalid.",
"INVALID_STACK": "The stack at '{{cell}}' is not yours.",
"INVALID_TARGET": "The cell '{{cell}}' is occupied.",
"MUST_PASS": "The only move available to you is to pass.",
"NO_KNIGHT": "The selected cell '{{cell}}' is not a knight's move away.",
"NO_NEIGHBORS": "The selected cell '{{cell}}' is not connected to the board.",
"NO_STACK": "There is no stack at '{{cell}}'.",
"SELECT_CELL": "Select a target cell.",
"SHORT_STACK": "The stack at '{{cell}}' cannot be split.",
"SPLIT_STACK": "Click either cell to redistribute the split of the stack. Click an empty cell or the Complete Move button to finish your turn."
},
"konane": {
"FIRST_MOVE": "Remove one of your pieces from the center 2x2 or from a corner.",
"SECOND_MOVE": "Remove one of your pieces adjacent to the piece your opponent removed.",
Expand Down
3 changes: 3 additions & 0 deletions locales/en/apresults.json
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,7 @@
"repetition_positional_one": "The game has ended because the same position has occurred.",
"repetition_positionas_other": "The game has ended because the same position has occurred {{count}} times.",
"stalemate": "The game has ended because one player has run out of moves.",
"stalemate_all": "The game has ended because all players have run out of moves.",
"stawvs": "The game has ended because the last player was unable to move.",
"susan_nonplacement": "The game has ended because no player has placed a piece for 6 plies.",
"tafl_encirclement": "The game has ended because the defenders are encircled.",
Expand Down Expand Up @@ -344,6 +345,7 @@
"gess_other": "{{player}} moved a 3x3 piece containing {{count}} stones from {{from}} to {{to}}.",
"hexentafl_king": "{{player}} moved the king from {{from}} to {{to}}.",
"iqishiqi": "{{player}} moved neutral stone {{from}} to {{to}}.",
"knightline": "{{player}} moved {{what}} pieces from {{from}} to {{to}}.",
"mattock": "{{player}} moved a miner from {{from}} to {{to}}.",
"meg": "{{player}} passed the ball from {{from}} to {{to}}.",
"monkey_queen": "{{player}} moved their queen from {{from}} to {{to}}.",
Expand Down Expand Up @@ -447,6 +449,7 @@
"gorogo_henge": "{{player}} placed a henge piece at {{where}}.",
"gorogo_piece": "{{player}} placed a piece at {{where}}.",
"iqishiqi": "{{player}} placed a shared stone at {{where}}.",
"knightline": "{{player}} placed their initial stack at {{where}}.",
"logger_logger": "{{player}} placed their logger at {{where}}.",
"logger_plant": "{{player}} planted a sapling at {{where}}.",
"logger_spawn": "A new sapling sprouted at {{where}}.",
Expand Down
9 changes: 7 additions & 2 deletions src/games/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,7 @@ import { EatYourNeighborGame, IEatYourNeighborState } from "./eatyourneighbor";
import { MutternlandGame, IMutternlandState } from "./mutternland";
import { IntermediumGame, IIntermediumState } from "./intermedium";
import { StapeldammenGame, IStapeldammenState } from "./stapeldammen";
import { KnightLineGame, IKnightLineState } from "./knightline";

export {
APGamesInformation, GameBase, GameBaseSimultaneous, IAPGameState,
Expand Down Expand Up @@ -549,6 +550,7 @@ export {
MutternlandGame, IMutternlandState,
IntermediumGame, IIntermediumState,
StapeldammenGame, IStapeldammenState,
KnightLineGame, IKnightLineState,
};

const games = new Map<string, typeof AmazonsGame | typeof BlamGame | typeof CannonGame |
Expand Down Expand Up @@ -643,7 +645,7 @@ const games = new Map<string, typeof AmazonsGame | typeof BlamGame | typeof Cann
typeof CompartGame | typeof AkimboGame | typeof CrossControlGame |
typeof UnstackGame | typeof SwarmGame | typeof EatYourNeighborGame |
typeof MutternlandGame | typeof IntermediumGame | typeof StapeldammenGame |
typeof CarnacGame | typeof DruidGame
typeof CarnacGame | typeof DruidGame | typeof KnightLineGame
>();
// Manually add each game to the following array
[
Expand Down Expand Up @@ -685,7 +687,7 @@ const games = new Map<string, typeof AmazonsGame | typeof BlamGame | typeof Cann
SynapseGame, AtariGoGame, TanboGame, UnaneGame, LinageGame, PolluxGame, PippinzipGame, NarrowsGame,
InvectorGame, TricouleurGame, PositGame, VirusWarGame, FormsGame, CompartGame, AkimboGame,
CrossControlGame, UnstackGame, SwarmGame, EatYourNeighborGame, MutternlandGame, IntermediumGame,
StapeldammenGame
StapeldammenGame, KnightLineGame
].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 @@ -1243,6 +1245,9 @@ export const GameFactory = (game: string, ...args: any[]): GameBase|GameBaseSimu
return new IntermediumGame(...args);
case "stapeldammen":
return new StapeldammenGame(...args);
case "knightline":
return new KnightLineGame(args[0], ...args.slice(1));

}
return;
}
Loading
Loading