{"id":20885726,"url":"https://github.com/sabakihq/gtp","last_synced_at":"2025-05-12T19:31:23.034Z","repository":{"id":47268387,"uuid":"128949315","full_name":"SabakiHQ/gtp","owner":"SabakiHQ","description":"A Node.js module for handling GTP engines.","archived":false,"fork":false,"pushed_at":"2020-07-18T00:40:18.000Z","size":288,"stargazers_count":19,"open_issues_count":1,"forks_count":9,"subscribers_count":3,"default_branch":"master","last_synced_at":"2024-11-10T04:15:17.393Z","etag":null,"topics":["ai","baduk","board-game","engine","go","gtp","nodejs","weiqi"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/SabakiHQ.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null},"funding":{"custom":"https://www.paypal.me/yishn/5"}},"created_at":"2018-04-10T14:48:44.000Z","updated_at":"2024-09-10T15:00:42.000Z","dependencies_parsed_at":"2022-09-05T07:31:34.805Z","dependency_job_id":null,"html_url":"https://github.com/SabakiHQ/gtp","commit_stats":null,"previous_names":[],"tags_count":33,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SabakiHQ%2Fgtp","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SabakiHQ%2Fgtp/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SabakiHQ%2Fgtp/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SabakiHQ%2Fgtp/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/SabakiHQ","download_url":"https://codeload.github.com/SabakiHQ/gtp/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":225148843,"owners_count":17428430,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ai","baduk","board-game","engine","go","gtp","nodejs","weiqi"],"created_at":"2024-11-18T08:14:19.349Z","updated_at":"2024-11-18T08:14:20.208Z","avatar_url":"https://github.com/SabakiHQ.png","language":"JavaScript","funding_links":["https://www.paypal.me/yishn/5"],"categories":[],"sub_categories":[],"readme":"# @sabaki/gtp [![CI](https://github.com/SabakiHQ/gtp/workflows/CI/badge.svg?branch=master\u0026event=push)](https://github.com/SabakiHQ/gtp/actions)\n\nA Node.js module for handling GTP engines.\n\n## Installation\n\nUse npm to install:\n\n```\n$ npm install @sabaki/gtp\n```\n\n## Usage\n\n### Controller Usage\n\nUse the [`Controller`](#controller) class to interact with an engine:\n\n```js\nconst {StreamController, Controller, Command, Response} = require('@sabaki/gtp')\n\nasync function main() {\n  let leela = new Controller('./path/to/leela', ['--gtp', '--noponder'])\n  leela.start()\n\n  let response = null\n\n  try {\n    response = await leela.sendCommand({name: 'genmove', args: ['B']})\n  } catch (err) {\n    throw new Error('Failed to send command!')\n  }\n\n  if (response.error) {\n    throw new Error('Command not understood by Leela!')\n  }\n\n  console.log(response.content)\n  await leela.stop()\n}\n\nmain().catch(err =\u003e console.log(`Error: ${err}`))\n```\n\n### Engine Usage\n\nUse the [`Engine`](#engine) class to create an engine:\n\n```js\nconst {Engine} = require('@sabaki/gtp')\n\nlet testEngine = new Engine('Test Engine', '0.1')\n\ntestEngine.command('play', (command, out) =\u003e {\n  if (command.args.length === 0) return out.err('player not specified')\n  out.send('playing for ' + command.args[0])\n})\n\ntestEngine.start()\n```\n\n## API\n\n### `Command`\n\nA GTP command is represented by an object of the following form:\n\n```js\n{\n  id?: \u003cInteger\u003e | null,\n  name: \u003cString\u003e,\n  args?: \u003cString[]\u003e\n}\n```\n\n#### `Command.fromString(input)`\n\n- `input` `\u003cString\u003e` - The GTP command as string, e.g. `1 genmove B`\n\nReturns a `Command` object, representing `input`.\n\n#### `Command.toString(command)`\n\n- `command` [`\u003cCommand\u003e`](#command)\n\nReturns a GTP command string represented by `command` to be sent to an engine.\n\n---\n\n### `Response`\n\nA response from a GTP engine is represented by an object of the following form:\n\n```js\n{\n  id?: \u003cInteger\u003e | null,\n  content: \u003cString\u003e,\n  error?: \u003cBoolean\u003e\n}\n```\n\n#### `Response.fromString(input)`\n\n- `input` `\u003cString\u003e` - The GTP response as string, e.g. `=1 ok`\n\nReturns a `Response` object, representing `input`.\n\n#### `Response.toString(response)`\n\n- `response` [`\u003cResponse\u003e`](#response)\n\nReturns a GTP response string represented by `response`, something that an\nengine might send.\n\n---\n\n### `class StreamController extends EventEmitter`\n\nUse this class to control GTP engines on arbitrary communication channels. To\nspawn engine processes automatically, use [`Controller`](#controller).\n\n#### `new StreamController(input, output)`\n\n- `input`\n  [`\u003cWritable\u003e`](https://nodejs.org/api/stream.html#stream_class_stream_writable)\n- `output`\n  [`\u003cReadable\u003e`](https://nodejs.org/api/stream.html#stream_class_stream_readable)\n\n#### Event: `command-sent`\n\n- `evt` `\u003cObject\u003e`\n  - `command` [`\u003cCommand\u003e`](#command)\n  - `subscribe(subscriber)`\n  - `async getResponse()` [`\u003cResponse\u003e`](#response)\n\nThis event is emitted when a command is sent to the engine. Using the\n`subscribe` function you can get updates every time the engine responds with a\nnew line, see\n[streamController.sendCommand()](#async-streamcontrollersendcommandcommand-subscriber).\n\n#### Event: `response-received`\n\n- `evt` `\u003cObject\u003e`\n  - `command` [`\u003cCommand\u003e`](#command)\n  - `response` [`\u003cResponse\u003e`](#response)\n\nThis event is emitted when the engine finishes sending a response.\n\n#### `streamController.input`\n\n[`\u003cWritable\u003e`](https://nodejs.org/api/stream.html#stream_class_stream_writable) -\nThe input stream of the GTP engine.\n\n#### `streamController.output`\n\n[`\u003cReadable\u003e`](https://nodejs.org/api/stream.html#stream_class_stream_readable) -\nThe output stream of the GTP engine.\n\n#### `streamController.commands`\n\n[`\u003cCommand[]\u003e`](#command) - The command queue.\n\n#### `streamController.busy`\n\n`\u003cBoolean\u003e` - Indicates whether the controller is waiting for an engine response\nor not.\n\n#### `async streamController.sendCommand(command[, subscriber])`\n\n- `command` [`\u003cCommand\u003e`](#command)\n- `subscriber` `\u003cFunction\u003e` _(optional)_\n  - `evt` `\u003cObject\u003e`\n\nSends a command to the engine and returns a [response object](#response). You\ncan pass a `subscriber` function to get updates every time the engine responds\nwith a new line. `subscriber` is called with an object `evt` with the following\nproperties:\n\n- `line` `\u003cString\u003e` - The contents of the incoming line.\n- `end` `\u003cBoolean\u003e` - `true` if incoming line is the last line of response.\n- `command` [`\u003cCommand\u003e`](#command) - The command to which the response belongs.\n- `response` [`\u003cResponse\u003e`](#response) - The partial response until now,\n  including the incoming line with all the previous lines.\n\n#### `streamController.close()`\n\nCleans up listeners.\n\n---\n\n### `class Controller extends EventEmitter`\n\nUse this class to spawn GTP engine processes and control them over `stdin` and\n`stdout`.\n\n#### `new Controller(path[, args[, spawnOptions]])`\n\n- `path` `\u003cString\u003e`\n- `args` `\u003cString[]\u003e` _(optional)_\n- `spawnOptions` `\u003cObject\u003e` _(optional)_ - See\n  [Node.js documentation](https://nodejs.org/api/child_process.html#child_process_child_process_spawn_command_args_options).\n\n#### Event: `started`\n\nThis event is emitted when the engine process starts.\n\n#### Event: `stopped`\n\n- `evt` `\u003cObject\u003e`\n  - `signal` `\u003cString\u003e` - The signal by which the engine process was terminated.\n\nThis event is emitted after the engine process ends.\n\n#### Event: `stderr`\n\n- `evt` `\u003cObject\u003e`\n  - `content` `\u003cString\u003e`\n\nThis event is emitted when the engine process finishes printing a line on\nstderr.\n\n#### Event: `command-sent`\n\nSee [corresponding event in `StreamController`](#event-command-sent).\n\n#### Event: `response-received`\n\nSee [corresponding event in `StreamController`](#event-response-received).\n\n#### `controller.path`\n\n`\u003cString\u003e` - The path to an executable file, the GTP engine.\n\n#### `controller.args`\n\n`\u003cString[]\u003e` - Additional arguments that are passed to the engine when started.\n\n#### `controller.spawnOptions`\n\n`\u003cObject\u003e` - See\n[Node.js documentation](https://nodejs.org/api/child_process.html#child_process_child_process_spawn_command_args_options).\n\n#### `controller.process`\n\n[`\u003cChildProcess\u003e`](https://nodejs.org/api/child_process.html) | `null` - The GTP\nengine process.\n\n#### `controller.commands`\n\n[`\u003cCommand[]\u003e`](#command) - The command queue.\n\n#### `controller.busy`\n\n`\u003cBoolean\u003e` - Indicates whether the controller is waiting for an engine response\nor not.\n\n#### `controller.start()`\n\nSpawns a process of the engine if necessary.\n\n#### `async controller.stop([timeout])`\n\n- `timeout` `\u003cnumber\u003e` _(optional)_ - Default: `3000`\n\nSends a `quit` command to the engine. If engine doesn't respond, it will be\nkilled after `timeout` ms.\n\n#### `async controller.kill()`\n\nKills the engine process.\n\n#### `async controller.sendCommand(command[, subscriber])`\n\nSee\n[corresponding function in `StreamController`](#async-streamcontrollersendcommandcommand-subscriber).\n\n---\n\n### `class ControllerStateTracker`\n\nUse this class to keep track of the state of an engine. This class is also able\nto synchronize the state of an engine to a given state.\n\n#### `EngineState`\n\nThe state of an engine is represented by an object of the following structure:\n\n```js\n{\n  komi: \u003cnumber\u003e,\n  boardsize: \u003c[number, number]\u003e,\n  timeSettings: {\n    mainTime: \u003cnumber\u003e,\n    byoyomiTime: \u003cnumber\u003e,\n    byoyomiStones: \u003cnumber\u003e\n  },\n  history: \u003cCommand[]\u003e\n}\n```\n\n- Values will be `null` if we do not know the engine state.\n- `boardsize` contains the width and height of the board.\n- `history` is an array of `set_free_handicap` and `play` [commands](#command).\n\n#### `new ControllerStateTracker(controller)`\n\n- `controller` [`\u003cStreamController\u003e`](#streamcontroller) or\n  [`\u003cController\u003e`](#controller)\n\n#### `ControllerStateTracker.fromStreamController(input, output)`\n\nEquivalent to `new ControllerStateTracker(new StreamController(input, output))`.\n\n#### `ControllerStateTracker.fromController(path[, args[, spawnOptions]])`\n\nEquivalent to\n`new ControllerStateTracker(new Controller(path, args, spawnOptions))`.\n\n#### `stateTracker.controller`\n\n[`\u003cStreamController\u003e`](#streamcontroller) or [`\u003cController\u003e`](#controller) - The\ncontroller of the engine that we're tracking the state of.\n\n#### `stateTracker.state`\n\n[`\u003cEngineState\u003e`](#enginestate) - The state of the engine controlled by\n[`stateTracker.controller`](#statetrackercontroller).\n\n#### `stateTracker.syncing`\n\n`\u003cBoolean\u003e` - Indicates whether the controller is performing a sync right now.\n\n#### `async stateTracker.knowsCommand(commandName)`\n\n- `commandName` `\u003cString\u003e`\n\nReturns a boolean whether the engine supports the given command.\n\n#### `async stateTracker.queueCommand(command)`\n\n- `command` [`\u003cCommand\u003e`](#command)\n\nSends the given command to the engine after all ongoing syncs have finished and\nreturns the response.\n\n#### `async stateTracker.sync(state)`\n\n- `state` [`\u003cEngineState\u003e`](#enginestate)\n\nTries to sync the engine to the given `state`. Omit keys or set values to `null`\nin the `state` object if you do not want to change the engine state for\nparticular keys.\n\n---\n\n### `class Engine extends EventEmitter`\n\nUse this class to create a GTP engine using the communication channels of your\nchoice.\n\n#### `new Engine([name[, version]])`\n\n- `name` `\u003cString\u003e` _(optional)_\n- `version` `\u003cString\u003e` _(optional)_\n\nThe following GTP commands have a default implementation:\n\n- `protocol_version`\n- `name`\n- `version`\n- `list_commands`\n- `quit`\n\n#### Event: `started`\n\nThis event is emitted when the engine has started.\n\n#### Event: `stopped`\n\nThis event is emitted when the engine has stopped.\n\n#### Event: `command-received`\n\n- `evt` `\u003cObject\u003e`\n  - `command` [`\u003cCommand\u003e`](#command)\n\nThis event is emitted after a command has been received.\n\n#### Event: `command-processing`\n\n- `evt` `\u003cObject\u003e`\n  - `command` [`\u003cCommand\u003e`](#command)\n\nThis event is emitted when a command is about to be processed.\n\n#### Event: `command-processed`\n\n- `evt` `\u003cObject\u003e`\n  - `command` [`\u003cCommand\u003e`](#command)\n  - `response` [`\u003cResponse\u003e`](#response)\n\nThis event is emitted after a command has been processed.\n\n#### `engine.handlers`\n\n`\u003cObject\u003e` - An object with the command names as keys, and handler functions as\nvalues.\n\n#### `engine.commands`\n\n[`\u003cCommand[]\u003e`](#command) - The command queue.\n\n#### `engine.busy`\n\n`\u003cBoolean\u003e` - If `true`, a command is being processed right now.\n\n#### `engine.command(name, handler)`\n\n- `name` `\u003cString\u003e` - The command name.\n- `handler` `\u003cFunction\u003e` | `\u003cString\u003e`\n\nSets a handler for the given command. `handler` will be called with the\nfollowing arguments:\n\n- `command` [`\u003cCommand\u003e`](#command)\n- `out` `\u003cObject\u003e`\n  - `send(content)` - Sends a successful response with the given content.\n  - `err(content)` - Sends an error response with the given content.\n  - `write(content)` - Writes given content to response.\n  - `end()` - When using `write`, use this method to indicate end of response.\n\n`handler` can be an `async` function or return a `Promise`. In this case, you\ndon't need to call `out.end()` explicitly.\n\nYou can also pass a string as `handler` to immediately return a response.\n\n#### `engine.start([options])`\n\n- `options` `\u003cObject\u003e` _(optional)_\n  - `input`\n    [`\u003cReadable\u003e`](https://nodejs.org/api/stream.html#stream_class_stream_readable)\n    _(optional)_ - Default: `process.stdin`\n  - `output`\n    [`\u003cWritable\u003e`](https://nodejs.org/api/stream.html#stream_class_stream_writable)\n    _(optional)_ - Default: `process.stdout`\n\nStarts listening to commands.\n\n#### `engine.stop()`\n\nStops listening.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsabakihq%2Fgtp","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsabakihq%2Fgtp","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsabakihq%2Fgtp/lists"}