Progress on Rustic

Discussion of chess software programming and technical issues.

Moderators: hgm, Rebel, chrisw

User avatar
mvanthoor
Posts: 1784
Joined: Wed Jul 03, 2019 4:42 pm
Location: Netherlands
Full name: Marcel Vanthoor

Re: Progress on Rustic

Post by mvanthoor »

Terje wrote: Fri Oct 23, 2020 3:21 am ucinewgame should reset TT and any other stuff you keep from turn to turn during a single game - could be things like previous turns final search depth, whether you saved time last move and want to spend more the coming turn etc. In Weiss this is still just clearing TT and resetting number of failed queries to chessdb.cn if using NoobBook.

It doesn't have to reset the board (though it doesn't hurt); a position command must be sent before each go command. Setting up the board on startup is nice for humans doing a quick manual test, but manually playing a full game and starting a new one ucing UCI in a terminal seems unlikely.
I've implemented a custom command "board" so I could test the "position fen | startpos [moves ...]" implementation. The protocol is actually unclear about this. (This: http://wbec-ridderkerk.nl/html/UCIProtocol.html) It actually says "position fen | startpos [moves ...]", which made it look like as if the FEN-string goes where "fen" is declared now. It doesn't, according to arena. The command actually is "position fen <fen_string> | startpos [moves ...]"

Also, what to do if "moves" contains an illegal move? I use my engine's internal move generator and make move to determine if "e2e4" is actually a possible pseudo-move. Then I execute it, but if it's illegal, it will be unmade, obviously. I tested this in Texel 1.07, and if to, from, and promotion piece are legal, it actually just moves the piece on the board. If you start with "position startpos moves e2d6" and then "go", it will capture the pawn on d6.

In my engine, I can't even do that, except if I start to just flip bits and actually circumvent the engine itself.

Assuming a GUI never accepts illegal moves and never sends illegal moves (or wrongly formatted FEN-strings), I've decided to not worry about that, and:

- Try to set up the FEN. If it fails, print a message and don't change the board. (Useful if someone is using the engine through the console; it already functions like this internally.)
- Try to execute moves. As soon as there is an illegal one, print a message pointing out this move, and stop processing the move list.

This seems to work fine; it uses the engine's own error checking facilities. The only thing I had to add was to print a message in case someone is putting this in through the console. (And so I can, should I want to, log communication and retrace it.)

(As an example: here, d5d4 puts the king in check so the engine won't have you execute this move.)

Code: Select all

$ ./target/release/rustic.exe

d888888b                      dP   oo
88     88                     88
88oooo88  88    88  d8888b  d8888P dP d88888b
88    88  88    88  8ooooo    88   88 88
88     88 88    88       88   88   88 88
88     88  88888P  888888P    dP   dP 888888P
ooooooooooooooooooooooooooooooooooooooooooooo

Engine: Rustic Alpha 1
Author: Marcel Vanthoor
EMail: mail@marcelvanthoor.nl
Website: https://rustic-chess.org/
Protocol: uci
Threads: 1

position fen 8/3p4/8/4k3/8/8/Q7/5K2 w - - 0 1 moves a2a5 d7d5 f1e2 d5d4
d5d4: This is not a legal move in this position.
board

8   . . . . . . . .
7   . . . . . . . .
6   . . . . . . . .
5   Q . . i k . . .
4   . . . . . . . .
3   . . . . . . . .
2   . . . . K . . .
1   . . . . . . . .

    A B C D E F G H

Zobrist key:        250d5801f898ffd7
Active Color:       Black
Castling:
En Passant:         -
Half-move clock:    1
Full-move number:   2
Getting close, keep at it :)
Thanks; almost there. I hope to be able to play a testing game this weekend :)
Author of Rustic, an engine written in Rust.
Releases | Code | Docs | Progress | CCRL
User avatar
mvanthoor
Posts: 1784
Joined: Wed Jul 03, 2019 4:42 pm
Location: Netherlands
Full name: Marcel Vanthoor

Re: Progress on Rustic

Post by mvanthoor »

It is beginning to come alive :) The engine now has enough of the UCI-protocol implemented to be able to analyse in a GUI keep it updated.

Image

The engine's speed on a i7-6700K, 1 CPU, is about 2.000 kNodes/s (+/- 200 kNodes/s depending on the position). It hits depth 7 instantly, depth 8 after about 3-4 seconds, and depth 9 in 6-7 seconds. Note that the engine still doesn't have anything like killer moves, heuristics, or a hash table to speed up search. (It also doesn't have QSearch yet, and doesn't extract a PV short of the currently best found move at the last completed depth.)

I think the engine's speed is not going to be a bottleneck in reaching a decent playing strength. (The target is 2895 Elo on CCRL 40/15, 1CPU. At that speed, it'll be stronger than Frtiz 11 1CPU, on-par with Glaurung 2.2 4CPU, and it'll be in the top 100; at least at this time of writing. It'll take some time I assume...)

So, it's connected to a GUI now. It works in Fritz 17 and Arena. I'll install Fritz 11 again, so I assume it'll work there as well. Later I'll test it in CuteChess and other GUI's. Now it's just a matter of piling more UCI-commands on top of it, and add QSearch, a TT, killers, and heurustics.

Using the threading system and passing information through channels actually makes adding new commands surprisingly easy. I add the command, parse it, put the results into a struct and send it to the engine thread. In there, the engine reacts accordingly, either by doing something itself, or sending messages to Comm or Search.

The Comm module can now handle this, for example:

Code: Select all

pub enum CommControl {
    Update,                           // Request Comm module to update its state.
    Quit,                             // Quit the Comm module.
    Identify,                         // Transmit identification of the engine.
    Ready,                            // Transmit that the engine is ready.
    SearchSummary(SearchSummary),     // Transmit search information.
    SearchCurrent(SearchCurrentMove), // Transmit currently considered move.
    SearchStats(SearchStats),         // Transmit search Statistics.
    InfoString(String),               // Transmit general information.
    BestMove(Move),                   // Transmit the engine's best move.

    // Output to screen when running in a terminal window.
    PrintBoard,
    PrintHelp,
}
The current UCI module outputs this stuff as UCI strings; I can obviously also output this in CECP/XBoard format or whatever other format may be required in the future. (And if a protocol doesn't support one of these features, it can just be ignored.)
Author of Rustic, an engine written in Rust.
Releases | Code | Docs | Progress | CCRL
User avatar
hgm
Posts: 27810
Joined: Fri Mar 10, 2006 10:06 am
Location: Amsterdam
Full name: H G Muller

Re: Progress on Rustic

Post by hgm »

mvanthoor wrote: Fri Oct 23, 2020 10:00 amI've implemented a custom command "board" so I could test the "position fen | startpos [moves ...]" implementation. The protocol is actually unclear about this. (This: http://wbec-ridderkerk.nl/html/UCIProtocol.html) It actually says "position fen | startpos [moves ...]", which made it look like as if the FEN-string goes where "fen" is declared now. It doesn't, according to arena. The command actually is "position fen <fen_string> | startpos [moves ...]"
The problem is that that page is damaged / wrongly installed. Someone called it .html, but it does does not contain any true HTML; it is written in plain text, which someone just put between <pre></pre> tags. The result is that meta symbols like <fenstring> that appear in the BNF syntax descriptions are interpreted by the browser as (unknown, and thus ignored) HTML tags.

Try to view it as 'Page Source" to see the entire document. The line you quote then shows up as

* position [fen <fenstring> | startpos ] moves <move1> .... <movei>
User avatar
Guenther
Posts: 4610
Joined: Wed Oct 01, 2008 6:33 am
Location: Regensburg, Germany
Full name: Guenther Simon

Re: Progress on Rustic

Post by Guenther »

hgm wrote: Sat Oct 24, 2020 3:11 pm
mvanthoor wrote: Fri Oct 23, 2020 10:00 amI've implemented a custom command "board" so I could test the "position fen | startpos [moves ...]" implementation. The protocol is actually unclear about this. (This: http://wbec-ridderkerk.nl/html/UCIProtocol.html) It actually says "position fen | startpos [moves ...]", which made it look like as if the FEN-string goes where "fen" is declared now. It doesn't, according to arena. The command actually is "position fen <fen_string> | startpos [moves ...]"
The problem is that that page is damaged / wrongly installed. Someone called it .html, but it does does not contain any true HTML; it is written in plain text, which someone just put between <pre></pre> tags. The result is that meta symbols like <fenstring> that appear in the BNF syntax descriptions are interpreted by the browser as (unknown, and thus ignored) HTML tags.

Try to view it as 'Page Source" to see the entire document. The line you quote then shows up as

* position [fen <fenstring> | startpos ] moves <move1> .... <movei>
Also it is from April 2004, there is a newer draft (2006) directly from the Shredder site (SMK the inventor of uci).
http://download.shredderchess.com/div/uci.zip

There are a few differences/corrections (and FRC = Chess960 support was added too).
For the position thing it is identical though to what HG posted.

Code: Select all

* position [fen <fenstring> | startpos ]  moves <move1> .... <movei>
	set up the position described in fenstring on the internal board and
	play the moves on the internal chess board.
	if the game was played  from the start position the string "startpos" will be sent
	Note: no "new" command is needed. However, if this position is from a different game than
	the last position sent to the engine, the GUI should have sent a "ucinewgame" inbetween.
https://rwbc-chess.de

trollwatch:
Talkchess nowadays is a joke - it is full of trolls/idiots/people stuck in the pleistocene > 80% of the posts fall into this category...
User avatar
mvanthoor
Posts: 1784
Joined: Wed Jul 03, 2019 4:42 pm
Location: Netherlands
Full name: Marcel Vanthoor

Re: Progress on Rustic

Post by mvanthoor »

Thanks both :) I found the revised version when looking for Chess960 stuff. That's a variant I'm going to definitely support at some time, as I want to start playing it more myself.
Author of Rustic, an engine written in Rust.
Releases | Code | Docs | Progress | CCRL
Ras
Posts: 2488
Joined: Tue Aug 30, 2016 8:19 pm
Full name: Rasmus Althoff

Re: Progress on Rustic

Post by Ras »

mvanthoor wrote: Fri Oct 23, 2020 10:00 amAlso, what to do if "moves" contains an illegal move?
If that is the case, or if the FEN is illegal (not exactly two kings, side to move giving check, ...), I print "info string error (problem description)" so that a GUI can display this. I also invalidate the position so that attempting a "go" command will yield "bestmove 0000" as response. Transmitting a valid "position" command or "ucinewgame" will reset this error state.
Rasmus Althoff
https://www.ct800.net
User avatar
mvanthoor
Posts: 1784
Joined: Wed Jul 03, 2019 4:42 pm
Location: Netherlands
Full name: Marcel Vanthoor

Re: Progress on Rustic

Post by mvanthoor »

Ras wrote: Sat Oct 24, 2020 4:04 pm
mvanthoor wrote: Fri Oct 23, 2020 10:00 amAlso, what to do if "moves" contains an illegal move?
If that is the case, or if the FEN is illegal (not exactly two kings, side to move giving check, ...), I print "info string error (problem description)" so that a GUI can display this. I also invalidate the position so that attempting a "go" command will yield "bestmove 0000" as response. Transmitting a valid "position" command or "ucinewgame" will reset this error state.
Thanks. That is also an option. I now send "info string Error in FEN. The board has not been changed." (And it hasn't.) If there is an illegal move, I send "info string Move (move here) is not a legal move. Stopped processing moves." In that case, the board is correct up to the previous move.

I don't know which way is 'better' or idiomatic. Your way may confuse a user interface. For instance, if I start Infinite Analysis" in Fritz/Chessbase, it sends "go infinite", and when the option is disabled, it sends "stop". It expects, and then ignores, "bestmove". If this command doesn't come, the GUI will hang for about 30 seconds waiting for it, and then it'll kill the engine. With your solution, "bestmove" won't come. With mine, it will... but it may be a move the GUI does not expect. I don't know if the GUI will then ignore the move with an error, or if it will kill the engine.

I'll try and test these things when I have more of the UCI-protocol implemented.

But you are correct with regarding the FEN: At some point, I will have to extend FEN legality checking to not only having a correctly formed string, but also having a legal position. (Not more than 9 queens or 10 R/B/N, not more than 8 pawns, at least one pawn less per promotion, 2 kings, and side to move not in check.)
Author of Rustic, an engine written in Rust.
Releases | Code | Docs | Progress | CCRL
Ras
Posts: 2488
Joined: Tue Aug 30, 2016 8:19 pm
Full name: Rasmus Althoff

Re: Progress on Rustic

Post by Ras »

mvanthoor wrote: Sat Oct 24, 2020 4:13 pmIt expects, and then ignores, "bestmove".
Which I'd send immediately with "bestmove 0000". Of course, it might trip up the GUI if it discards this and starts only scanning for "bestmove" after it has sent "stop". I could of course also delay the "bestmove 0000" in case of "go infinite" so that the engine would just wait for "stop" without sending analysis info.
Rasmus Althoff
https://www.ct800.net
User avatar
hgm
Posts: 27810
Joined: Fri Mar 10, 2006 10:06 am
Location: Amsterdam
Full name: H G Muller

Re: Progress on Rustic

Post by hgm »

mvanthoor wrote: Sat Oct 24, 2020 4:13 pm(Not more than 9 queens or 10 R/B/N, not more than 8 pawns, at least one pawn less per promotion, 2 kings, and side to move not in check.)
Can your engine really not handle that? If it could, such pedantic checking would only break your engine for positions it could otherwise handle, for no reason. E.g. people could no longer play "Charge of the Light Brigade" with it (3 Queens vs 7 Knights in the presence of 8 Pawns each.)

Positions it cannot handle it should of course refuse. But why intentionally sabotage it for things that some people might want to do with it?
User avatar
mvanthoor
Posts: 1784
Joined: Wed Jul 03, 2019 4:42 pm
Location: Netherlands
Full name: Marcel Vanthoor

Re: Progress on Rustic

Post by mvanthoor »

hgm wrote: Sat Oct 24, 2020 4:36 pm
mvanthoor wrote: Sat Oct 24, 2020 4:13 pm(Not more than 9 queens or 10 R/B/N, not more than 8 pawns, at least one pawn less per promotion, 2 kings, and side to move not in check.)
Can your engine really not handle that? If it could, such pedantic checking would only break your engine for positions it could otherwise handle, for no reason. E.g. people could no longer play "Charge of the Light Brigade" with it (3 Queens vs 7 Knights in the presence of 8 Pawns each.)

Positions it cannot handle it should of course refuse. But why intentionally sabotage it for things that some people might want to do with it?
You have a point there. At this point, the engine can handle any position that uses standard chess pieces on a 8x8 board, except if the position has more than one king per side. So adding checks specific to standard chess would invalidate deriving engines from Rustic that play chess variants. (The only real problem would be chess variants that use other board sizes than 8x8, but at this point I don't plan to implement any of those.)

There are some (G)UI's that only or mainly use CECP (and some people just dislike UCI), so I intended to implement this so people can use the engine without any adapters in the (G)UI they prefer. If I remember this correctly, isn't it so that Winboard/XBoard can support many chess variants, or be configured to do so? In that case, it would be an excellent reason to implement CECP in the engine, apart form just trying to cater to everybody's tastes.

There actually are some chess variants I like. It's a pity they are impossible to play on a DGT-board as there are no (G)UI's or pieces that support them. The only one that would be possible is CrazyHouse as it uses only standard chess pieces.
Author of Rustic, an engine written in Rust.
Releases | Code | Docs | Progress | CCRL