Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
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.
- Host: GitHub
- URL: https://github.com/sabakihq/gtp
- Owner: SabakiHQ
- License: mit
- Created: 2018-04-10T14:48:44.000Z (over 6 years ago)
- Default Branch: master
- Last Pushed: 2020-07-18T00:40:18.000Z (over 4 years ago)
- Last Synced: 2024-11-10T04:15:17.393Z (about 1 month ago)
- Topics: ai, baduk, board-game, engine, go, gtp, nodejs, weiqi
- Language: JavaScript
- Homepage:
- Size: 281 KB
- Stars: 19
- Watchers: 3
- Forks: 9
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
- Funding: .github/FUNDING.yml
- License: LICENSE
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.