Skip to content

Instantly share code, notes, and snippets.

@artfuldev
Last active October 31, 2024 15:57
Show Gist options
  • Save artfuldev/47ef277cf4bbbfdf0eed4750b8821c8c to your computer and use it in GitHub Desktop.
Save artfuldev/47ef277cf4bbbfdf0eed4750b8821c8c to your computer and use it in GitHub Desktop.
Simple Tic-Tac-Toe Protocol

ST3P

Simple Tic-Tac-Toe Protocol

Overview

ST3P is a text-based protocol facilitating communication between Tic-Tac-Toe engines and UI/coordinator processes.

The protocol operates over standard input and output, supporting standalone native processes.

Versioning

The protocol supports versioning to ensure compatibility and facilitate updates.

Initial handshake involves the UI/coordinator and the engine agreeing on the protocol version. Versions are positive integers to avoid ambiguity in sequence. The versions are expected to be backwards compatible.

In the documentation below, commands and options will carry a Minimum Supported Version Number (MSVN) which enables those commands and options. If unspecified, its MSVN is 1. Any version of the protocol above the specified version will support those commands. Recall that the protocol enforces backwards compatibility.

Protocol

The protocol is line-based, with each line representing a single command. The protocol is expected to be case-sensitive, with lowercase taking precedence It's text-based for readability and is designed to be backwards-compatible.

If the engine or coordinator receives an unknown or unexpected command or token it is expected to ignore it and continue parsing the rest of the string.

The engine should always be able to process input from stdin, even while thinking.

In all following examples, > is from ui/coordinator to engine, and < is from engine to ui/coordinator. All lines are terminated with a \n (LF).

Handshake

Upon booting the engine, the UI/coordinator shares the protocol name and version, to which the engine responds with an acknowledgement of the name and version with an ok. Note that even if the version of the engine is much higher it has to respond and operate at the same level as the UI / coordinator. As the protocol is backwards compatible this should not be an issue.

Example:

> st3p version 1
< st3p version 1 ok

Engine Identification

The UI/coordinator can optionally request engine details using the identify command, to which the engine responds with its name, author, version, and any relevant URL. These are sent in separate lines with an identify prefix so after the keys the string is taken as is. After sending all details for identification the engine sends identify ok.

> identify
< identify name random-step
< identify author [email protected]
< identify version 1.0.0
< identify url https://github.com/artfuldev/random-step
< identify ok

Gameplay

The UI/coordinator sends a move command to the engine, with the current state of the game in T3EN format. This describes the board and the side to move. The engine is expected to respond with the best <move>.

If the engine fails to respond (or within the constraints), or responds with an invalid move, the game is lost.

Time Controls

Time controls are optional, and the time is assumed to be infinite if no time control options are present. If multiple time control options are present, the latest one takes precedence.

time ms:<x>

The move should be played in <x> milliseconds. If the engine does not respond with a best <move> within this time, the game is lost.

time-remaining ms:<x>

The game should be played in <x> milliseconds by the side to play. The engine can use a portion of the time as determined by it for this move. Time-based wins apply.

Options

win-length <x> (MSVN 2)

The game should be considered won by one of the sides if they manage to occupy consecutive cells of length <x>. This is only provided when playing at smaller win lengths than the default (which is dynamic per row, column, and diagonal, consisting of all playable cells in the row, column, and diagonal respectively).

Move Specification

The move is specified as a string of the form <x><y> where x is the column name (from left to right) and y is the row number (1-indexed, from top to bottom). This is akin to a spreadsheet. The row-numbers are natural numbers and the column names go from a to z and then aa to zz and so on.

As an example the top-left cell of a standard 3x3 board is a1 and the bottom-right cell is c3.

For a larger 27x27 board, the top-left cell is a1 and the bottom-right cell is aa27.

Examples

> move 3_/3_/3_ x
< best b2
> move 3_/_x_/3_ o
< best c3
> move _2x/_x_/2o_ o
< best c3
> move 3_/3_/3_ x time ms:1000
< best b2
> move 3_/3_/3_ x time-remaining ms:10000
< best b2
MSVN 2
> move 5_/5_/5_/5_/5_ x win-length 3
< best d4
> move 15_/15_/15_/15_/15_/15_/15_/15_/15_/15_/15_/15_/15_/15_/15_ x time ms:10000 win-length 5
< best h8

Termination

The quit command is used by the UI/coordinator to terminate the engine session. The engine should exit as soon as possible, cleaning up any resources used.

> quit

Acknowledgements

The protocol is inspired by the UCI protocol. The idea of choosing the cell references like seen in spreadsheets to aid in simplicity and familiarity was suggested by @shwethathammaiah.

@artfuldev
Copy link
Author

Thanks @SovG for the question.

Yes! The ideal execution model to think of is a user interface that can interrupt the engine at any time with a new command, and the engine is supposed to respond to the latest command immediately upon receiving a new command, completely not worrying about any previous outputs it may have wanted to send as the result of any earlier commands.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment