A Node.js module for handling GTP engines.
Use npm to install:
$ npm install @sabaki/gtp
Use the Controller
class to interact with an engine:
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}`))
Use the Engine
class to create an engine:
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()
A GTP command is represented by an object of the following form:
{
id?: <Integer> | null,
name: <String>,
args?: <String[]>
}
input
<String>
- The GTP command as string, e.g.1 genmove B
Returns a Command
object, representing input
.
command
<Command>
Returns a GTP command string represented by command
to be sent to an engine.
A response from a GTP engine is represented by an object of the following form:
{
id?: <Integer> | null,
content: <String>,
error?: <Boolean>
}
input
<String>
- The GTP response as string, e.g.=1 ok
Returns a Response
object, representing input
.
response
<Response>
Returns a GTP response string represented by response
, something that an
engine might send.
Use this class to control GTP engines on arbitrary communication channels. To
spawn engine processes automatically, use Controller
.
input
<Writable>
output
<Readable>
evt
<Object>
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().
evt
<Object>
command
<Command>
response
<Response>
This event is emitted when the engine finishes sending a response.
<Writable>
-
The input stream of the GTP engine.
<Readable>
-
The output stream of the GTP engine.
<Command[]>
- The command queue.
<Boolean>
- Indicates whether the controller is waiting for an engine response
or not.
command
<Command>
subscriber
<Function>
(optional)evt
<Object>
Sends a command to the engine and returns a response object. 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
<String>
- The contents of the incoming line.end
<Boolean>
-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.
Cleans up listeners.
Use this class to spawn GTP engine processes and control them over stdin
and
stdout
.
path
<String>
args
<String[]>
(optional)spawnOptions
<Object>
(optional) - See Node.js documentation.
This event is emitted when the engine process starts.
evt
<Object>
signal
<String>
- The signal by which the engine process was terminated.
This event is emitted after the engine process ends.
evt
<Object>
content
<String>
This event is emitted when the engine process finishes printing a line on stderr.
See corresponding event in StreamController
.
See corresponding event in StreamController
.
<String>
- The path to an executable file, the GTP engine.
<String[]>
- Additional arguments that are passed to the engine when started.
<Object>
- See
Node.js documentation.
<ChildProcess>
| null
- The GTP
engine process.
<Command[]>
- The command queue.
<Boolean>
- Indicates whether the controller is waiting for an engine response
or not.
Spawns a process of the engine if necessary.
timeout
<number>
(optional) - Default:3000
Sends a quit
command to the engine. If engine doesn't respond, it will be
killed after timeout
ms.
Kills the engine process.
See
corresponding function in StreamController
.
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.
The state of an engine is represented by an object of the following structure:
{
komi: <number>,
boardsize: <[number, number]>,
timeSettings: {
mainTime: <number>,
byoyomiTime: <number>,
byoyomiStones: <number>
},
history: <Command[]>
}
- 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 ofset_free_handicap
andplay
commands.
controller
<StreamController>
or<Controller>
Equivalent to new ControllerStateTracker(new StreamController(input, output))
.
Equivalent to
new ControllerStateTracker(new Controller(path, args, spawnOptions))
.
<StreamController>
or <Controller>
- The
controller of the engine that we're tracking the state of.
<EngineState>
- The state of the engine controlled by
stateTracker.controller
.
<Boolean>
- Indicates whether the controller is performing a sync right now.
commandName
<String>
Returns a boolean whether the engine supports the given command.
command
<Command>
Sends the given command to the engine after all ongoing syncs have finished and returns the response.
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.
Use this class to create a GTP engine using the communication channels of your choice.
name
<String>
(optional)version
<String>
(optional)
The following GTP commands have a default implementation:
protocol_version
name
version
list_commands
quit
This event is emitted when the engine has started.
This event is emitted when the engine has stopped.
evt
<Object>
command
<Command>
This event is emitted after a command has been received.
evt
<Object>
command
<Command>
This event is emitted when a command is about to be processed.
evt
<Object>
command
<Command>
response
<Response>
This event is emitted after a command has been processed.
<Object>
- An object with the command names as keys, and handler functions as
values.
<Command[]>
- The command queue.
<Boolean>
- If true
, a command is being processed right now.
name
<String>
- The command name.handler
<Function>
|<String>
Sets a handler for the given command. handler
will be called with the
following arguments:
command
<Command>
out
<Object>
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 usingwrite
, 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.
options
<Object>
(optional)input
<Readable>
(optional) - Default:process.stdin
output
<Writable>
(optional) - Default:process.stdout
Starts listening to commands.
Stops listening.