Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/sabakihq/gtp

A Node.js module for handling GTP engines.
https://github.com/sabakihq/gtp

ai baduk board-game engine go gtp nodejs weiqi

Last synced: about 1 month ago
JSON representation

A Node.js module for handling GTP engines.

Awesome Lists containing this project

README

        

# @sabaki/gtp [![CI](https://github.com/SabakiHQ/gtp/workflows/CI/badge.svg?branch=master&event=push)](https://github.com/SabakiHQ/gtp/actions)

A Node.js module for handling GTP engines.

## Installation

Use npm to install:

```
$ npm install @sabaki/gtp
```

## Usage

### Controller Usage

Use the [`Controller`](#controller) class to interact with an engine:

```js
const {StreamController, Controller, Command, Response} = require('@sabaki/gtp')

async function main() {
let leela = new Controller('./path/to/leela', ['--gtp', '--noponder'])
leela.start()

let response = null

try {
response = await leela.sendCommand({name: 'genmove', args: ['B']})
} catch (err) {
throw new Error('Failed to send command!')
}

if (response.error) {
throw new Error('Command not understood by Leela!')
}

console.log(response.content)
await leela.stop()
}

main().catch(err => console.log(`Error: ${err}`))
```

### Engine Usage

Use the [`Engine`](#engine) class to create an engine:

```js
const {Engine} = require('@sabaki/gtp')

let testEngine = new Engine('Test Engine', '0.1')

testEngine.command('play', (command, out) => {
if (command.args.length === 0) return out.err('player not specified')
out.send('playing for ' + command.args[0])
})

testEngine.start()
```

## API

### `Command`

A GTP command is represented by an object of the following form:

```js
{
id?: | null,
name: ,
args?:
}
```

#### `Command.fromString(input)`

- `input` `` - The GTP command as string, e.g. `1 genmove B`

Returns a `Command` object, representing `input`.

#### `Command.toString(command)`

- `command` [``](#command)

Returns a GTP command string represented by `command` to be sent to an engine.

---

### `Response`

A response from a GTP engine is represented by an object of the following form:

```js
{
id?: | null,
content: ,
error?:
}
```

#### `Response.fromString(input)`

- `input` `` - The GTP response as string, e.g. `=1 ok`

Returns a `Response` object, representing `input`.

#### `Response.toString(response)`

- `response` [``](#response)

Returns a GTP response string represented by `response`, something that an
engine might send.

---

### `class StreamController extends EventEmitter`

Use this class to control GTP engines on arbitrary communication channels. To
spawn engine processes automatically, use [`Controller`](#controller).

#### `new StreamController(input, output)`

- `input`
[``](https://nodejs.org/api/stream.html#stream_class_stream_writable)
- `output`
[``](https://nodejs.org/api/stream.html#stream_class_stream_readable)

#### Event: `command-sent`

- `evt` ``
- `command` [``](#command)
- `subscribe(subscriber)`
- `async getResponse()` [``](#response)

This event is emitted when a command is sent to the engine. Using the
`subscribe` function you can get updates every time the engine responds with a
new line, see
[streamController.sendCommand()](#async-streamcontrollersendcommandcommand-subscriber).

#### Event: `response-received`

- `evt` ``
- `command` [``](#command)
- `response` [``](#response)

This event is emitted when the engine finishes sending a response.

#### `streamController.input`

[``](https://nodejs.org/api/stream.html#stream_class_stream_writable) -
The input stream of the GTP engine.

#### `streamController.output`

[``](https://nodejs.org/api/stream.html#stream_class_stream_readable) -
The output stream of the GTP engine.

#### `streamController.commands`

[``](#command) - The command queue.

#### `streamController.busy`

`` - Indicates whether the controller is waiting for an engine response
or not.

#### `async streamController.sendCommand(command[, subscriber])`

- `command` [``](#command)
- `subscriber` `` _(optional)_
- `evt` ``

Sends a command to the engine and returns a [response object](#response). You
can pass a `subscriber` function to get updates every time the engine responds
with a new line. `subscriber` is called with an object `evt` with the following
properties:

- `line` `` - The contents of the incoming line.
- `end` `` - `true` if incoming line is the last line of response.
- `command` [``](#command) - The command to which the response belongs.
- `response` [``](#response) - The partial response until now,
including the incoming line with all the previous lines.

#### `streamController.close()`

Cleans up listeners.

---

### `class Controller extends EventEmitter`

Use this class to spawn GTP engine processes and control them over `stdin` and
`stdout`.

#### `new Controller(path[, args[, spawnOptions]])`

- `path` ``
- `args` `` _(optional)_
- `spawnOptions` `` _(optional)_ - See
[Node.js documentation](https://nodejs.org/api/child_process.html#child_process_child_process_spawn_command_args_options).

#### Event: `started`

This event is emitted when the engine process starts.

#### Event: `stopped`

- `evt` ``
- `signal` `` - The signal by which the engine process was terminated.

This event is emitted after the engine process ends.

#### Event: `stderr`

- `evt` ``
- `content` ``

This event is emitted when the engine process finishes printing a line on
stderr.

#### Event: `command-sent`

See [corresponding event in `StreamController`](#event-command-sent).

#### Event: `response-received`

See [corresponding event in `StreamController`](#event-response-received).

#### `controller.path`

`` - The path to an executable file, the GTP engine.

#### `controller.args`

`` - Additional arguments that are passed to the engine when started.

#### `controller.spawnOptions`

`` - See
[Node.js documentation](https://nodejs.org/api/child_process.html#child_process_child_process_spawn_command_args_options).

#### `controller.process`

[``](https://nodejs.org/api/child_process.html) | `null` - The GTP
engine process.

#### `controller.commands`

[``](#command) - The command queue.

#### `controller.busy`

`` - Indicates whether the controller is waiting for an engine response
or not.

#### `controller.start()`

Spawns a process of the engine if necessary.

#### `async controller.stop([timeout])`

- `timeout` `` _(optional)_ - Default: `3000`

Sends a `quit` command to the engine. If engine doesn't respond, it will be
killed after `timeout` ms.

#### `async controller.kill()`

Kills the engine process.

#### `async controller.sendCommand(command[, subscriber])`

See
[corresponding function in `StreamController`](#async-streamcontrollersendcommandcommand-subscriber).

---

### `class ControllerStateTracker`

Use this class to keep track of the state of an engine. This class is also able
to synchronize the state of an engine to a given state.

#### `EngineState`

The state of an engine is represented by an object of the following structure:

```js
{
komi: ,
boardsize: <[number, number]>,
timeSettings: {
mainTime: ,
byoyomiTime: ,
byoyomiStones:
},
history:
}
```

- Values will be `null` if we do not know the engine state.
- `boardsize` contains the width and height of the board.
- `history` is an array of `set_free_handicap` and `play` [commands](#command).

#### `new ControllerStateTracker(controller)`

- `controller` [``](#streamcontroller) or
[``](#controller)

#### `ControllerStateTracker.fromStreamController(input, output)`

Equivalent to `new ControllerStateTracker(new StreamController(input, output))`.

#### `ControllerStateTracker.fromController(path[, args[, spawnOptions]])`

Equivalent to
`new ControllerStateTracker(new Controller(path, args, spawnOptions))`.

#### `stateTracker.controller`

[``](#streamcontroller) or [``](#controller) - The
controller of the engine that we're tracking the state of.

#### `stateTracker.state`

[``](#enginestate) - The state of the engine controlled by
[`stateTracker.controller`](#statetrackercontroller).

#### `stateTracker.syncing`

`` - Indicates whether the controller is performing a sync right now.

#### `async stateTracker.knowsCommand(commandName)`

- `commandName` ``

Returns a boolean whether the engine supports the given command.

#### `async stateTracker.queueCommand(command)`

- `command` [``](#command)

Sends the given command to the engine after all ongoing syncs have finished and
returns the response.

#### `async stateTracker.sync(state)`

- `state` [``](#enginestate)

Tries to sync the engine to the given `state`. Omit keys or set values to `null`
in the `state` object if you do not want to change the engine state for
particular keys.

---

### `class Engine extends EventEmitter`

Use this class to create a GTP engine using the communication channels of your
choice.

#### `new Engine([name[, version]])`

- `name` `` _(optional)_
- `version` `` _(optional)_

The following GTP commands have a default implementation:

- `protocol_version`
- `name`
- `version`
- `list_commands`
- `quit`

#### Event: `started`

This event is emitted when the engine has started.

#### Event: `stopped`

This event is emitted when the engine has stopped.

#### Event: `command-received`

- `evt` ``
- `command` [``](#command)

This event is emitted after a command has been received.

#### Event: `command-processing`

- `evt` ``
- `command` [``](#command)

This event is emitted when a command is about to be processed.

#### Event: `command-processed`

- `evt` ``
- `command` [``](#command)
- `response` [``](#response)

This event is emitted after a command has been processed.

#### `engine.handlers`

`` - An object with the command names as keys, and handler functions as
values.

#### `engine.commands`

[``](#command) - The command queue.

#### `engine.busy`

`` - If `true`, a command is being processed right now.

#### `engine.command(name, handler)`

- `name` `` - The command name.
- `handler` `` | ``

Sets a handler for the given command. `handler` will be called with the
following arguments:

- `command` [``](#command)
- `out` ``
- `send(content)` - Sends a successful response with the given content.
- `err(content)` - Sends an error response with the given content.
- `write(content)` - Writes given content to response.
- `end()` - When using `write`, use this method to indicate end of response.

`handler` can be an `async` function or return a `Promise`. In this case, you
don't need to call `out.end()` explicitly.

You can also pass a string as `handler` to immediately return a response.

#### `engine.start([options])`

- `options` `` _(optional)_
- `input`
[``](https://nodejs.org/api/stream.html#stream_class_stream_readable)
_(optional)_ - Default: `process.stdin`
- `output`
[``](https://nodejs.org/api/stream.html#stream_class_stream_writable)
_(optional)_ - Default: `process.stdout`

Starts listening to commands.

#### `engine.stop()`

Stops listening.