SkillAgentSearch skills...

Tafl

A library for Hnefatafl (Viking Chess, or Tafl) that is used for move generation/validation, piece placement/movement, and game over detection. You can use it to simulate games between AI agents - although you need to write the agents yourself :)

Install / Use

/learn @demircancelebi/Tafl
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

tafl

A Typescript library for Hnefatafl (Viking Chess, or Tafl) that is used for move generation/validation, piece placement/movement, and game over detection.

You can use it to simulate games between AI agents - although you need to write the agents yourself :)

Installation

npm install tafl

Features

This library has support for these:

  • [X] Exit forts: Defenders can build exit forts (edge forts) on the sides for the king to run and win the game
  • [X] Shieldwall: Both sides can capture multiple pieces on the sides with shieldwall captures
  • [X] Repetition checks: Game ends on 3-fold repetition. The repeating board states do not have to be in succession. You can modify this number (3) through rules.
  • [X] If attackers surround all defender pieces, game ends
  • [X] If any side has no moves left, they lose
  • [X] King can escape from edges optionally (in addition to corners, usually used in smaller boards)
  • [X] King can be armed or not. Armed kings can help with capturing pieces.
  • [X] King can return to center or not. In some variations of the game, returning to center base is forbidden.
  • [X] Attackers can capture the king with 2, 3, or 4 pieces. In Copenhagen, king has to be surrounded from 4 sides, but this behavior can be modified.
  • [X] Setting the starting side for the game. In Copenhagen, attackers start the game.
  • [X] Changing the width of corners. Usually corners are one square, but in Alea Evangelii variation, corners are 2x2

You can use the library with an arbitrary game state. (set the board/rules as you'd like and start using the library from that game state, useful for setting up specific board states)

Basic example

Uses Copenhagen rules on 11x11 board, plays both sides with random agent

const { Tafl } = require('tafl')

const tafl = new Tafl()
let state = tafl.initialState() // by default uses Copenhagen rules on 11x11 board with the classical starting position, you can use a different state if you want

while (!state.result.finished) {
  const possibleActions = tafl.getPossibleActions(state)
  const randomAction = possibleActions[Math.floor(Math.random() * possibleActions.length)];

  state = tafl.act(state, randomAction)
}

tafl.log({ turn: state.turn, result: state.result, lastAction: state.lastAction, board: state.board })
// -> { turn: 604,
//      result: { finished: true, winner: 'Defender', desc: 'King escaped from corner' },
//      lastAction: { from: { r: 10, c: 2 }, to: { r: 10, c: 0 } },
//      board:
//       [ [ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' ],
//         [ ' ', ' ', ' ', ' ', ' ', 'A', ' ', ' ', ' ', ' ', ' ' ],
//         [ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' ],
//         [ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' ],
//         [ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', 'A', 'A', 'A' ],
//         [ 'D', 'A', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', 'A' ],
//         [ ' ', ' ', 'A', ' ', ' ', ' ', 'A', ' ', ' ', ' ', 'A' ],
//         [ ' ', ' ', ' ', ' ', 'A', ' ', ' ', 'A', ' ', 'A', ' ' ],
//         [ ' ', ' ', ' ', ' ', 'D', 'A', ' ', 'A', ' ', ' ', ' ' ],
//         [ ' ', ' ', ' ', ' ', ' ', ' ', ' ', 'A', 'A', 'A', ' ' ],
//         [ 'K', ' ', ' ', ' ', ' ', ' ', 'A', ' ', ' ', ' ', ' ' ] ] }

API

You can import these different objects:

const { Piece, TaflBoard, TaflRule, TaflRuleSet, Tafl } = require('tafl')

Piece

Used as an enum. Has __ key for empty places, PA for attackers, PD for defenders, and PK for king.

console.log(Piece)
// -> { __: ' ', PA: 'A', PD: 'D', PK: 'K' }

TaflBoard

You can pass a custom board to the tafl.initialState. Here are some of the starting positions of different variations for the game, you can use these or pass a custom board when creating initial state. See examples for usage.

  • TaflBoard._7_BRANDUBH
  • TaflBoard._9_TABLUT
  • TaflBoard._11_CLASSIC
  • TaflBoard._11_LINE
  • TaflBoard._11_TAWLBWRDD
  • TaflBoard._11_LEWISS
  • TaflBoard._13_PARLETT
  • TaflBoard._15_DAMIEN_WALKER
  • TaflBoard._19_ALEA_EVANGELII

TaflRule

Used as an enum, and maps to string values. Use these to change the behavior of the game. See examples for usage.

| TaflRule name | Type | Default (In TaflRuleset.COPENHAGEN ) | Description | |---------------|-------|---------------------------------|--------------| | TaflRule.EXIT_FORTS | Boolean | true | Exit forts | | TaflRule.SHIELD_WALLS | Boolean | true | Shieldwall captures | | TaflRule.EDGE_ESCAPE | Boolean | false | King can escape from edges (in addition to corners, usually used in smaller boards) | | TaflRule.KING_IS_ARMED | Boolean | true | King armed or not | | TaflRule.KING_CAN_RETURN_TO_CENTER | Boolean | true | King can return to center or not | | TaflRule.ATTACKER_COUNT_TO_CAPTURE | Number | 4 | Attackers can capture with 2, 3, or 4 pieces | | TaflRule.STARTING_SIDE | TaflSide | TaflSide.ATTACKER | Game starts with attackers or defenders | | TaflRule.CORNER_BASE_WIDTH | Number | 1 | Width of corners, usually corners are one piece, but in Alea Evangelii variation, corners are 2x2 | | TaflRule.REPETITION_TURN_LIMIT | Number | 3 | Repetition turn limit (On copenhagen game draws on Threefold repetition, you can modify this number). You can disable draw on repetititon by setting TaflRule.SAVE_BOARD_HISTORY to false | | TaflRule.SAVE_BOARD_HISTORY | Boolean | true | If set to false, repetition checks are disabled. If you are running many simulations and can live without repetition checks, set to false as it may allow an order of magnitude more simulations in a given time. Otherwise should be true. | | TaflRule.SAVE_ACTIONS | Boolean | true | Saving actions may not be required for simulations. Although this has a tiny effect on performance, you may want to set this to false too. |

TaflRuleSet

Used as an enum, used for grouping rules to access with a single name. Only has COPENHAGEN value for now. See examples for usage.

  • TaflRuleSet.COPENHAGEN

Examples

Start with Copenhagen on 7x7 Brandubh board, allow edge escape and use 2x2 corners:

const { Tafl, TaflBoard, TaflRule, TaflRuleSet } = require('tafl')

const tafl = new Tafl()
let state = tafl.initialState({
  board: TaflBoard._7_BRANDUBH,
  rules: {
    ...TaflRuleSet.COPENHAGEN,
    [TaflRule.EDGE_ESCAPE]: true,
    [TaflRule.CORNER_BASE_WIDTH]: 2,
    [TaflRule.SAVE_BOARD_HISTORY]: false
  }
})

while (!state.result.finished) {
  const possibleActions = tafl.getPossibleActions(state)
  const randomAction = possibleActions[Math.floor(Math.random() * possibleActions.length)];

  state = tafl.act(state, randomAction)
}

tafl.log({ turn: state.turn, result: state.result, lastAction: state.lastAction, board: state.board })
// -> { turn: 12,
//      result: { finished: true, winner: 'Defender', desc: 'King escaped from edge' },
//      lastAction: { from: { r: 4, c: 3 }, to: { r: 4, c: 6 } },
//      board:
//       [ [ ' ', ' ', 'A', 'A', 'D', ' ', ' ' ],
//         [ ' ', ' ', ' ', ' ', ' ', ' ', ' ' ],
//         [ ' ', 'A', ' ', 'D', ' ', 'A', ' ' ],
//         [ 'A', ' ', ' ', ' ', ' ', ' ', 'A' ],
//         [ 'D', ' ', ' ', ' ', ' ', ' ', 'K' ],
//         [ ' ', ' ', 'D', 'A', ' ', ' ', ' ' ],
//         [ ' ', ' ', ' ', 'A', ' ', ' ', ' ' ] ] }

Interfaces & properties & methods

Interfaces

interface Named {
  name: String;
}
interface Coords {
  readonly r: number;
  readonly c: number;
}
interface MoveAction {
  from: Coords;
  to: Coords;
}
interface Game extends Named {
  getPossibleActions(state: GameState): MoveAction[];
  isActionPossible(state: GameState, action: MoveAction): boolean;
  isGameOver(state: GameState): typeof state;
  act(state: GameState, action: MoveAction): typeof state;
}

export declare type Board = Array<Array<Piece>>;
export interface GameState {
  board?: Board;
  actions?: Array<MoveAction>;
  boardHistory?: Record<string, number>;
  turn?: number;
  result?: {
    finished: boolean;
    winner?: TaflSide;
    desc: string;
  };
  captures?: Array<Coords>;
  lastAction?: MoveAction;
  rules?: {
    [key: string]: TaflRule;
  };
}

Properties & Methods

Full list of methods and properties, taken from type definitions file and is subject to change.

name: string;
controlMap: Map<TaflSide, Set<Piece>>;
sideMap: Map<Piece, TaflSide>;
initialState(init?: GameState): GameState;
log(thing: any): void;
isCenter(board: Board, coords: Coords): boolean;
isCorner(state: GameState, coords: Coords): boolean;
isEdge(state: GameState, coords: Coords): boolean;
repr(coords: Coords): String;
coords(repr: String): Coords;
toPathRepr(...args: Array<Coords>): String;
toPathCoords(path: String): Array<Coords>;
insideBounds(board: Board, coords: Coords): boolean;
connectedPieces(board: Board, coords: Coords, side: TaflSide): Set<String>;
connectedDefenders(board: Board, coords: Coords): Set<String>;
connectedAttackers(board: Board, coords: Coords): Set<String>;
possiblySurroundingPieces(board: Board, kingCoords: Coords, side: TaflSide): Array<Coords>;
possiblySurrondingDefenders(board: Board, kingCoords: Coords): Array<Coords>;
possiblySurrondingAttackers(board: Board, kingCoords: Coords): Array<Coords>;
isInsideEye(board: Board, coords: Coords, fullFortStructure: Set<String>): boolean;
getPossibleSmallestFortStructure(board: Board, innerSet: Set<String>, fullStructure: Set<String>): Set<String>;
getEmptyPiecesAndOpponentsInsideSmallestClosedStructure(board: Board, kingCoords: Coords, closedStructure: Set<String>, oppSide?: TaflSide): Array<Set<String>>;
getEmptyPiecesAndAttackersInsideSmallestFort(board: Board, kingCoords: Coords, fullFortStructure: Set<String>): Array<Set<String>>;
insideFort(board: Board, kingCoords: Coords): boolean;
kingEscapedThroughFort(state: GameState): boolean;
isBase(state: GameState, coords: Coords): boolean;
isEmpty(b

Related Skills

View on GitHub
GitHub Stars37
CategoryDevelopment
Updated1mo ago
Forks6

Languages

TypeScript

Security Score

95/100

Audited on Feb 21, 2026

No findings