[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Backgammon Protocol
From: |
Frank Berger |
Subject: |
Backgammon Protocol |
Date: |
Sun, 26 Nov 2023 19:02:30 +0100 |
Hi all,
> what do you mean with "you should do error handling for http“?
>
> You only have to handle the errors the API specify. My API draft specifies
> exactly two error codes:
> - 400 for client errors like „opponent has 16 checkers on the board“
> - 500 for server errors like „could not find neural network files“
I may be bit pedantic, but http has a lot of features. If some sends a correct
request or response and it doesn’t get handled properly I don’t like that.
If I ignore everything and only look for the error code, why use http in the
first place? What value http adds what we don’t get with pure streams?
>
> Every other error code returned by the server is then basically an
> implementation bug.
>
> Those errors need to be handled anyway. I believe HTTP and it’s libraries
> make this super easy to implement, otherwise you had to reinvent it.
Reinvention are about 10 lines of code (o.k. maybe 20). And if I have two way
to communicate an error either by status code or in the body doesn’t look right
to me.
>
> I also believe that there should be two mechanisms. The binary one could be
> simple C function calls, similar to what Øystein wrote in his email. Pure
> functions preferred.
>
> Something in that direction exists in wildbg:
> https://github.com/carsten-wenderdel/wildbg/blob/main/docs/user/wildbg-c.md
> https://github.com/carsten-wenderdel/wildbg/blob/main/crates/wildbg-c/wildbg.h
I would delay that until we have a clearer picture what we need. Nevertheless I
would strongly prefer somethings that is not tied to a language.
>
> This could also be the first step for GnuBG. The engine and the GUI could
> communicate via those C calls, no new library needed, everything compiled to
> one binary.
> External developers could then be able to compile GnuBG without the GUI and
> its GTK dependencies and use it as a C library.
>
> Around this C library we could then write a wrapper with a text based
> protocol. As so many languages support interfacing with C, we could even pick
> the language here.
>
> I don’t believe in two text based protocols building on top of each other. If
> there is a telnet/string based one and a HTTP based one, they would be two
> different protocols.
> If both had to be implemented, the implementations would be independent from
> each other.
I believe that the typical use case will be on a local machine and stdin/stdout
has a lot of advantages, e.g. you can start several instances without conflicts.
When you have a port, you must negotiate the port. What if there are two
clients? What if two servers? What if two version of the same server?
I don’t believe that the average user even understands what a port is. And
creating a server socket usually brings up a warning from the firewall, at
least some people might be irritated.
That all vanishes with stdin/stdout.
Nevertheless it is a charming idea not to have install something, just enter an
URL and try something out that is not on my computer.
But as Guido already pointed out: it would be trivial to forward from
stdin/stdout to a server.
What I don’t understand is why there should be different protocols for raw
network (socket, not telnet or ssh) vs. stdin/stdout?
In both cases I send either text and read text (let’s say JSON or its binary
counterpart).
>
> There is a lot we seem to have in common with our ideas. Is this right?
> - It’s a good idea to separate engine and GUI.
> - It should be a server/client model, so the GUI asks, the engine answers.
> - Stateless, no match information in the engine.
I think that is out of question.
As a proposal for a protocol see the following stuff. It is part from the
protocol that is used by BGBlitz server. I cut off some parts that make no
sense here, and what’s missing is feature negotiation.
Due to the customer demand their might be further things to be removed (e.g. to
handle droppers the move number is given ). It is both XML and JSON, I just
kept the XML stuff to avoid accidentally delete some info, I wont suggest XML.
Given that this protocol has served about 20 customers some of them large, it
probably contains what we need, it might just be trimmed down a bit.
The Evaluation Request is probably not important, because it s mostly about
evaluation a position and calculating payments if a game is interrupted.
The TutorRequest gives back a cube decision or a list of moves, depending
whether dice are set. I don’t expect you to read that, just scroll down to see
the requests and if you think it looks reasonable you may read the fine print.
If there is some acceptance I would rewrite the spec to JSON only and think
about better names in this context and what is necessary. I would also provide
some example code, maybe it is not daily business for one or the other to use
sockets, but it is not much more difficult than handling a file.
ciao
Frank
The Evaluation Request
======================
the evaluation request gets a position, described by the given parameters. A
position might be
from money game or a match, the dice may be given.
The EvalRequest may contain an id-attribute. It is optional (and only in the
response if present in the request)
and may be used to match request and response.
Explanation of the tags:
- <comment> a comment can be added to any request. This may be helpful for
debugging purposes.
This tag is optional.
- <attr name="cubeful" value="true"/> Shall BGBlitz use cubeful or cubeless
evaluations for
this request. Cubeful evaluations have the advantage, that they
reflect the reality
more precise, so a Dropper can't exploit the settlement algorithm
in any way. The
advantage of cubeless equity is, that the player can easily
calculate the values so
it might lead to less calls at the hotline.
This tag is optional; if missing the value is taken from the setup
- <attr name="ply" value="2"/> the number of half moves BGBlitz evaluates.
Valid values are 1,2
and 3. On a regular PC BGBlitz evaluates more than 100.000
positions per second. Each additional ply costs
about the factor of 30. E.g. 3-ply with no dice costs around 1
second. I recommend 2-ply as default. Even
on 1-ply the evaluations will be very good.
This tag is optional; if missing the value is taken from the setup
- <attr name="limit" value="5"/> A limit may be set for money games, i.e. the
maximum amount
that can be lost in a single money game. This tag is optional.
- <attr name="basicBet" value="1"/> The monetary amount played for. This is
paid if a single
game with the doubling cube on 1 was played.
- <attr name="gammons" value="on"/> Shall gammons count? Values "on" (default)
and "off".
This tag is optional.
- <attr name="backgammons" value="off"/> Shall backgammons count? Values "on"
(default) and "off".
This tag is optional.
- <attr name="MoveNumber" value="1"/> A special and important parameter is the
"MoveNumber":
Imagine in a post Crawford game, the trailer will always double.
But what happens
if the leading player drops e.g. at a score -1:-2? The normal
evaluation don't
take into account that a double will follow, so the dropping player
has an
incentive to drop. Therefore if the move number is < 4 (I assume
the trailer forgets
to double if not doubled after 3 moves) BGBlitz treats it as if the
double has been
made. This tag is optional, but highly recommended.
- <position> describes the complete position
- <dice red='0' green='0'/> the dice for the red and green player
- <score red='0' green='0'/> the score in a match. Optional in
money game;
mandatory in match
- <attr name='matchLength' value='0'/> The length of a match. If matchLength
is 0 then it
is regarded as a a money game.
- <attr name='whosOn' value='green'/> Who's turn is it? Values are red,
green. Mandatory
- <attr name='crawford' value='false'/> In matchplay. Is this the Crawford
game?
- <attr name='usecube' value='true'/> Shall the doubling cube be used?
Optional.
- <attr name="jacoby" value="true"/> Usually only in money games. Is the
Jacoby
rule enabled (i.e. undoubled
gammons/backgammons
don't count)?
- <attr name='board'> describes the positions physical board
- <board cube='1' cubeowner='none'> who owns the cube? cube owner may be
red, green or none.
What value shows the cube. cube may be
1, 2, 4, ...
- <points>-2,-2,-2,-2,-3,-2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,2,0</points> The
checkers.
"green" checkers are coded as negative
integers, "red"
checkers as positive integers. points
starts with greens
1 point resp. reds 24 point. bar and
off are encoded
separately.
- <bar red='1' green='0'/> Checkers on the bar. Optional if no
checkers are on
the bar. The same encoding as in
points is used,
so green checkers are negative.
- <off red='9' green='-2'/> Checkers played off. Optional if all
checkers are in
play. The same encoding as in points
is used,
so green checkers are negative.
If a parameter isn't set, reasonable defaults are taken.
An complete request:
<?xml version="1.0" encoding="UTF-8" ?>
<EvalRequest id='1234ab'>
<comment>A comment describing the request, just for debugging</comment>
<attr name="cubeful" value="true"/>
<attr name="ply" value="2"/>
<attr name="limit" value="5"/>
<attr name="basicBet" value="1"/>
<attr name="gammons" value="on"/>
<attr name="MoveNumber" value="1"/>
<attr name="backgammons" value="off"/>
<position>
<dice red='0' green='0'/>
<score red='0' green='0'/>
<attr name='matchLength' value='0'/>
<attr name='whosOn' value='green'/>
<attr name='crawford' value='false'/>
<attr name='usecube' value='true'/>
<attr name="jacoby" value="true"/>
<attr name='board'>
<board cube='1' cubeowner='none'>
<points>-2,-2,-2,-2,-3,-2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,2,0</points>
<bar red='1' green='0'/>
<off red='9' green='-2'/>
</board>
</attr>
</position>
</EvalRequest>
or
{
"type":"EvalRequest",
"id":"1234ab",
"comment":"A comment describing the request, just for debugging",
"basicBet":1,
"cubeful":true,
"ply":2,
"limit":5,
"MoveNumber":1,
"gammons":"on",
"backgammons":"off",
"position": {
"matchLength":0,
"whosOn":"green",
"usecube":true,
"jacoby":true,
"crawford":false,
"dice": { "red":0, "green":0 },
"score": { "red":0, "green":0 },
"board" : {
"cube":2,
"cubeowner":"red",
"points": [-2,-2,-2,-2,-3,-2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,2,0],
"bar": { "red":1, "green":0 }
"off": { "red":9, "green":-2 }
}
}}
response:
Explanation of the tags:
- <probabilities redwin="13.4" redwing="0.1" redwinbg="0.0" greenwin="86.6"
greenwing="11.3" greenwinbg="0.2" />
redwin: The probability that red wins in percent.
redwing: The probability that red wins a gammon or backgammon in percent.
redwinbg: The probability that red wins a backgammon in percent.
greenwin: The probability that green wins in percent.
greenwing: The probability that green wins a gammon or backgammon in
percent.
greenwinbg: The probability that green wins a backgammon in percent.
Look out: The gammons and backgammons are included in the wins. The
backgammons are included in the gammons.
greenwin and redwin add up to 100.0.
- <MWP red="42.2" green="57.8"> In the case of a match gives the probability of
the match win in percent.
- <amountWon red="-0.78" green="0.78"/> Contains the amount the players
get/have to pay in currency if the
game would be interrupted in this moment. This value can be used
directly, just the rake has to be added.
An complete request:
<?xml version="1.0" encoding="UTF-8" ?>
<EvalResult id='1234ab'>
<probabilities redwin="13.4" redwing="0.1" redwinbg="0.0" greenwin="86.6"
greenwing="11.3" greenwinbg="0.2" />
<MWP red="42.2" green="57.8”/> <!-- in the case of a match -->
<EMG green="-0.123" red="0.123"/> <!-- in the case of a match && EMG is
set-->
<amountWon red="-0.78" green="0.78"/>
</EvalResult>
or
{
"type":"EvalResult",
"probabilities": {"greenWin":0.442, "greenWinG":0.099, "greenWinBG":0.004,
"redWin":0.558, "redWinG":0.145, "redWinBG":0.006 },
"MWP":{"green":0.155,"red":0.845},
"EMG": {"green":0.270, "red":-0.270}
"amountWon" : { "green":-0.69, "red":0.69 }
}
in the case of an error an error response is send:
<?xml version="1.0" encoding="UTF-8" ?>
<Error>
unstructured text containing an explanation what went wrong.
</Error>
or
{"type":"Error","message":"unstructured text"}
The Tutor Request
=================
The tutor request is similar to the EvalRequest. When the dice are given, a
list
of best moves with their evaluation is given back.
When no dice is given, the current evaluation is given and if the cube is
usable,
with the appropriate cube action. Only the attributes different to the
EvalRequest
are described here.
- <TutorRequest id='1234ab'> The starting tag is different.
The id-attribute is optional (and only in the response if present in
the request)
and may be used to match request and response.
- <attr name="noOfMoves" value="5"/> How many moves should be returned? Any
value greater 0 is valid.
- <attr name="beaver" value="true"/> Are beavers allowed?
- <attr name="noise" value="0.05"/> If you use BGBlitz server as opponent,
BGBlitz is even with 1-ply
much to strong for most opponents. Therefore you can add some noise to the
evaluations.
Values might be in the range between 0.05 up to 0.5. Greater values mean a
weaker level of play.
The noise tag is optional.
- <attr name="longCubeDecision" value="true"/> shall the equity values for the
possible
cube decisions are shown (only if not a mandatory double etc.)?
- <attr name="ply" value="2"/> different than in the evaluation request, you
can use ply = 0 here.
ply=0 selects the weak AI
request:
<?xml version="1.0" encoding="UTF-8" ?>
<TutorRequest id='1234ab'>
<comment>A comment describing the request, just for debugging</comment>
<attr name="noise" value="0.05"/>
<attr name="cubeful" value="true"/>
<attr name="gammons" value="on"/>
<attr name="backgammons" value="off"/>
<attr name="noOfMoves" value="5"/> <!-- any value greater 0 -->
<attr name="ply" value="2"/> <!-- optional; if missing
taking the value from setup -->
<position>
<dice red='0' green='0'/>
<score red='0' green='0'/>
<attr name='matchLength' value='0'/> <!-- if matchLength is 0
then it is a money game -->
<attr name='whosOn' value='green'/>
<attr name='crawford' value='false'/>
<attr name='usecube' value='true'/>
<attr name="jacoby" value="true"/>
<attr name="beaver" value="true"/>
<attr name='board'>
<board cube='1' cubeowner='none'> <!-- cubeowner may be
red,green or none -->
<points>-2,-2,-2,-2,-3,-2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,2,0</points>
<bar red='1' green='0'/> <!--optional if no checker on
the bar -->
<off red='9' green='-2'/> <!--optional if no checker
off -->
</board>
</attr>
</position>
</TutorRequest>
or
{
"type":"TutorRequest",
"id":"yz234",
"comment":"A comment describing the request, just for debugging<",
"noise":0.05,
"cubeful":true,
"gammons":"on",
"backgammons":"on",
"noOfMoves":"3",
"ply":2,
"position": {
"whosOn":"red",
"usecube":true,
"crawford":true,
"jacoby":true,
"dice": { "red":1, "green":2},
"score": { "red":0, "green":0},
"board" : {
"cube":2,
"cubeowner":"green",
"points": [2,0,0,0,0,-5,0,-4,0,0,0,5,-4,0,0,0,3,0,5,-1,0,0,0,-1]
}
}
}
response in the case of several moves:
- <TutorResult> The response tag.
- <move rank="1"> rank tells the rank of the move. Not strictly necessary
because the moves
always come in order from the best decreasing.
- <movePart from="8" to="5" /> A move consists out of several move parts. The
points are
always from the viewpoint of the moving player.
Special field names are "bar" and "off".
- <probabilities> exactly as in the evaluation response
- <moneyEquity green="0.073" red="-0.73"> The evaluation of the position it is
a money game.
- <MWP red="42.2" green="57.8"> The evaluation of the position it is
a match play.
<?xml version="1.0" encoding="UTF-8" ?>
<TutorResult id='1234ab'>
<move rank="1">
<movePart from="8" to="5" /> <!-- points always from the
viewpoint of the moving player -->
<movePart from="6" to="5" /> <!-- special filed names are "bar"
and "off" -->
<probabilities redwin="52.5" redwing="14.4" redwinbg="0.004"
greenwin="47.5" greenwing="12.2" greenwinbg="0.03" />
<moneyEquity green="0.073" red="-0.73"/> <!-- if money game -->
<MWP red="42.2" green="57.8"/> <!-- if matchplay -->
<EMG green="-0.123" red="0.123"/> <!-- in the case of a match && EMG
is set-->
</move>
<move rank="2">
<movePart from="8" to="5" />
<movePart from="24" to="23" />
<probabilities redwin="46.3" redwing="11.0" redwinbg="0.003"
greenwin="53.7" greenwing="14.1" greenwinbg="0.04" />
<moneyEquity green="0.059" red="-0.059"/> <!-- if money game -->
<MWP red="42.2" green="57.8"/> <!-- if matchplay -->
<EMG green="-0.123" red="0.123"/> <!-- in the case of a match &&
EMG is set-->
</move>
.... up to noOfMoves
</TutorResult>
or
{
"type":"TutorResult",
"id":"yz234",
"move": [
{
"rank":1
"movePart": [ {"from":"6", "to":"5"}, {"from":"13", "to":"11"} ],
"probabilities": {
"greenWin":0.518, "greenWinG":0.154, "greenWinBG":0.009, "redWin":0.482,
"redWinG":0.118, "redWinBG":0.004 },
"MWP": {"green":0.335, "red":0.665},
"EMG": {"green":-0.280, "red":0.280}
"moneyEquity": {"green":0.076, "red":-0.076}},
{
"rank":2,\n" +
"movePart": [ {"from":"6", "to":"5"}, {"from":"24", "to":"22"} ],
"probabilities": {
"greenWin":0.531, "greenWinG":0.138, "greenWinBG":0.006, "redWin":0.469,
"redWinG":0.106, "redWinBG":0.004 },
"moneyEquity": {"green":0.097, "red":-0.097}
"EMG": {"green":0.-270, "red":0.270}
"MWP": {"green":0.332, "red":0.668},
},
.... up to noOfMoves
response in the case of a evaluation/cube decision:
- <cubeDecision owner='hold' other='take' /> Owner is the one, having the cube
in access.
Possible values in cube decision
are
owner: togood/hold/double/redouble
other: accept/resign/beaver
<TutorResult>
<probabilities redwin="46.3" redwing="11.0" redwinbg="0.003"
greenwin="53.7" greenwing="14.1" greenwinbg="0.04" />
<moneyEquity value="0.073"/> <!-- if money game -->
<matchWinningProb value="0.073"/> <!-- if matchplay -->
<EMG green="-0.123" red="0.123"/> <!-- in the case of a match && EMG
is set-->
<cubeDecision owner='hold' other='take' />
</TutorResult>
as JSON
{
"type":"TutorResult",
"probabilities": {
"greenWin":0.512, "greenWinG":0.123, "greenWinBG":0.005, "redWin":0.488,
"redWinG":0.112, "redWinBG":0.004 },
"MWP": {"green":0.318, "red":0.682},
"cubeDecision": {"owner":"hold", "other":"accept"}
}
or if "longCubeDecision" is set
<TutorResult>
<probabilities redwin="46.3" redwing="11.0" redwinbg="0.003"
greenwin="53.7" greenwing="14.1" greenwinbg="0.04" />
<moneyEquity value="0.073"/> <!-- if money game -->
<matchWinningProb value="0.073"/> <!-- if matchplay -->
<EMG green="-0.123" red="0.123"/> <!-- in the case of a match && EMG is
set-->
<cubeDecision owner='hold' other='accept' noDouble='-0.036'
doubleTake='-0.385' doubleDrop='1.000' />
</TutorResult>
or as JSON
{
"type":"TutorResult",
"probabilities": {
"greenWin":0.512, "greenWinG":0.123, "greenWinBG":0.005, "redWin":0.488,
"redWinG":0.112, "redWinBG":0.004 },
"MWP": {"green":0.318, "red":0.682},
"cubeDecision": {"owner":"double", "other":"resign", "noDouble":0.596,
"doubleTake":0.755, "doubleDrop":0.596}
}
in the case of a problem an error response is send:
<?xml version="1.0" encoding="UTF-8" ?>
<Error>
unstructured text
</Error>
or as JSON
{"type":"Error","message":"unstructured text"}
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- Backgammon Protocol,
Frank Berger <=