# [`@bedard/hexchess`](https://github.com/scottbedard/hexchess)
[](https://github.com/scottbedard/hexchess/actions/workflows/build.yml)
[](https://codecov.io/gh/scottbedard/hexchess)
[](https://www.npmjs.com/package/@bedard/hexchess)
[](https://crates.io/crates/hexchess)
[](https://github.com/scottbedard/hexchess/blob/main/LICENSE)
A Rust / TypeScript library for [Gliński's hexagonal chess](https://en.wikipedia.org/wiki/Hexagonal_chess#Gli%C5%84ski's_hexagonal_chess), and the brain of [hexchess.club](https://hexchess.club).
<p align="center">
<a href="https://hexchess.club">
<img src="assets/hexchess.svg" width="500" />
</a>
</p>
## Installation
Install this package via NPM.
> Depending on your bundler and target, you may need plugins for [Web Assembly](https://developer.mozilla.org/en-US/docs/WebAssembly) and [top-level await](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/await#top_level_await) to utilize WASM bindings.
```
npm install @bedard/hexchess
pnpm install @bedard/hexchess
yarn add @bedard/hexchess
```
## Basic usage
The `Hexchess` class is a deserialized version of [Forsyth–Edwards Notation](https://en.wikipedia.org/wiki/Forsyth%E2%80%93Edwards_Notation). It contains the board state, current turn, en passant, and move numbers. Since castling is not a part of hexagonal chess, that section is omitted. The board data is stored as an array of `Piece | null`, sorted in FEN-order.
To create a game at the starting position, use `Hexchess.init`.
```ts
import { Hexchess } from '@bedard/hexchess'
const hexchess = Hexchess.init()
```
`Hexchess` instances have the following shape. The `board` represents an array of position values, sorted in FEN-order.
```ts
{
board: [
'b', 'q', 'b', 'k', 'n', null, 'b', null, 'n', 'r',
null, null, null, null, null, 'r', 'p', 'p', 'p', 'p',
'p', 'p', 'p', 'p', 'p', null, null, null, null, null,
null, null, null, null, null, null, null, null, null, null,
null, 'P', null, null, null, null, null, null, null, null,
null, 'P', null, 'P', null, null, null, null, null, null,
null, 'P', null, 'B', null, 'P', null, null, null, null,
null, 'P', null, null, 'B', null, null, 'P', null, null,
null, 'P', 'R', 'N', 'Q', 'B', 'K', 'N', 'R', 'P',
null
],
turn: 'w',
ep: null,
halfmove: 0,
fullmove: 1
}
```
The following methods are available for interacting with the game. A pair of constants named `initialPosition` and `positions` are available as well.
#### `apply`
Apply a whitespace separated sequence of moves.
```ts
const hexchess = Hexchess.init()
hexchess.apply('g4g5 e7e6 f5f6 e6f6')
hexchess.toString() // 'b/qbk/n1b1n/r5r/ppp1ppppp/5p5/6P4/4P6/3P1B1P3/2P2B2P2/1PRNQBKNRP1 w - 0 3'
```
#### `applyMove`
Apply a single move from `string` or `San`.
```ts
const hexchess = Hexchess.init()
hexchess.applyMove(San.parse('g4g6'))
hexchess.toString() // 'b/qbk/n1b1n/r5r/ppppppppp/11/5PP4/4P6/3P1B1P3/2P2B2P2/1PRNQBKNRP1 b - 0 1'
```
#### `applyMoveUnsafe`
Apply a single move from `string` or `San`, regardless of turn or legality.
```ts
const hexchess = Hexchess.init()
hexchess.applyMoveUnsafe('b1b6')
hexchess.toString() // 'b/qbk/n1b1n/r5r/ppppppppp/1P9/5P5/4P1P4/3P1B1P3/2P2B2P2/2RNQBKNRP1 b - 0 1'
```
#### `clone`
Deeply clone a `Hexchess` instance.
```ts
const hexchess = Hexchess.init()
const clone = hexchess.clone()
hexchess === clone // false
```
#### `currentMoves`
Get all current legal moves.
```ts
const hexchess = new Hexchess('1/3/5/7/9/11/5P5/11/11/11/11 w - 0 1')
const moves = hexchess.currentMoves()
moves.map(String) // ['f5f6, 'f5f7', ...]
```
#### `findKing`
Find FEN index for king belonging to `Color`.
```ts
const hexchess = Hexchess.init()
hexchess.findKing('b') // 3
hexchess.findKing('w') // 86
```
#### `get`
Get board value from position name.
```ts
const hexchess = Hexchess.init()
hexchess.get('e1') // 'Q'
```
#### `getColor`
Get all board indices occupied by `Color` pieces.
```ts
const hexchess = Hexchess.init()
hexchess.getColor('b') // [0, 1, 2, ...]
```
#### `isCheck`
Test if the board is in check.
```ts
const hexchess = Hexchess.init()
isCheck(hexckess) // false
```
#### `isCheckmate`
Test if the game is in checkmate.
```ts
const hexchess = Hexchess.init()
isCheckmate(hexckess) // false
```
#### `isStalemate`
Test if the game is in stalemate.
```ts
const hexchess = Hexchess.init()
isStalemate(hexckess) // false
```
#### `movesFrom`
Get all legal moves from a position.
```ts
const hexchess = Hexchess.init()
const moves = hexchess.movesFrom('f6')
moves.map(String) // ['f6f7']
```
#### `movesFromUnsafe`
Get all moves from a position, including ones that result in self-check.
```ts
const hexchess = Hexchess.parse('1/3/5/7/4r4/5K5/11/11/11/11/11 w - 0 1')
const moves = hexchess.movesUnsafe()
moves.map(String) // ['f6f7', 'f6g7' ...]
```
#### `toString`
Serialize a `Hexchess` instance to string.
```ts
const hexchess = Hexchess.init()
hexchess.toString() // 'b/qbk/n1b1n/r5r/ppppppppp/11/5P5/4P1P4/3P1B1P3/2P2B2P2/1PRNQBKNRP1 w - 0 1'
```
## Wasm Bindings
The Rust crate for this library is exposed via WebAssembly. If your environment permits it, these are the functions you should use when writing engines or evaluators.
All APIs are the same as above, but with a functional syntax that accepts a `Hexchess` as the first argument, and returns a new `Hexchess` instance. The following methods are available to create and serialize objects.
```ts
import {
apply,
initHexchess,
stringifyHexchess,
} from '@bedard/hexchess/wasm' // <- note the import path
const hexchess = apply(initHexchess(), 'g4g6 f7g6 f5f7 g6f6')
stringifyHexchess(hexchess) // 'b/qbk/n1b1n/r5r/pppp1pppp/5p5/11/4P6/3P1B1P3/2P2B2P2/1PRNQBKNRP1 w - 0 3'
```
Below is a list of the available bindings.
- `apply`
- `applyMove`
- `applyMoveUnsafe`
- `createHexchess`
- `currentMoves`
- `findKing`
- `get`
- `initHexchess`
- `isCheck`
- `isCheckmate`
- `isStalemate`
- `movesFrom`
- `movesFromUnsafe`
- `parseHexchess`
- `parseSan`
- `stringifyHexchess`
- `stringifySan`
## License
[MIT](https://github.com/scottbedard/hexchess/blob/main/LICENSE)
Copyright (c) 2024-present, Scott Bedard