fairy-stockfish / Fairy-Stockfish

chess variant engine supporting Xiangqi, Shogi, Janggi, Makruk, S-Chess, Crazyhouse, Bughouse, and many more
https://fairy-stockfish.github.io/
GNU General Public License v3.0
603 stars 189 forks source link

Manual 64-move counting in makruk/ouk #76

Closed Fulmene closed 4 years ago

Fulmene commented 4 years ago

The 64-move counting rule of makruk states that the disadvantaged player may start counting. This is similar to how the fifty-move rule is manually claimed in chess.

There are also some other quirks with this rule. Firstly, the player may stop counting if he sees that he's now advantaged. And secondly, checkmate from the counting player who did not stop the count will result in a draw.

My concerns for implementing this are twofold:

ianfab commented 4 years ago

The questions you raised are the critical ones and I also do not have good answers yet.

One way of informing the engine about starting/stopping of counting might be via a (UCI) option type "button" (like Clear Hash), e.g., Start/Stop Counting. However, if the count of each position of the game should also be correctly reflected afterwards, pychess would need to store these actions and also apply them in replays of the game.

By the way, can both players count at the same time? Or can the opponent of the counting player claim a draw? If the answer to both questions would be no, then could the advantaged player start counting to prevent his opponent from doing so? (I guess not)

Fulmene commented 4 years ago

Regarding pychess, I'm fine with inaccurate counting in replays. I think reflecting the count correctly during play is enough. The benefit of implementing correct counting in replays is abysmal compared to how hard it seems to implement it.

Fulmene commented 4 years ago

By the way, can both players count at the same time?

No. The rule explicitly says only the disadvantaged player counts.

Can the opponent of the counting player claim a draw?

I'm not sure on this one, but I'm convinced it's a yes. I have some tournament rules statement, but there are different takes on this. I'll just put the sources here along with what they say. Sources (Thai): "While counting, the counting side is considered to be offering draw the entire time." http://bgsthai.com/2018/04/30/howtoplay/ "If the disadvantaged player sees that they can win, they must stop counting. If they don't, their opponent may claim a draw." http://www.lovemakrukthai.com/wp-content/uploads/2012/08/คู่มือกติกาหมากรุกสำหรับผู้เข้าแข่งขัน-ทุกสนาม.pdf "If the disadvantaged player sees that they can win, they must stop counting. If they don't, their win will be adjudicated as a draw." http://www.lovemakrukthai.com/wp-content/uploads/2012/10/กติกาการแข่งขันหมากรุกไทย-สมาคมกีฬาไทยในพระบรมราชูปถัมภ์.pdf

EDIT: The first source is the latest version of the rules, hosted on the official site of Thailand Sport Association, so I'll go with that and say definitely yes to this question.

Could the advantaged player start counting to prevent his opponent from doing so?

That's the abuse I'm concerned about. This usually doesn't arise in OTB play since an arbiter (or spectator in casual play) can verify which side is having advantage and act accordingly.

If you ask my opinion, I think implementing "opponent of the counting side may claim a draw" and "checkmate by the counting side is a draw" is the most elegant solution. This also means checkmate in the same turn as stopping the count is also a draw.

thaichessswinboard commented 4 years ago

At the endgame engine move wrong because it move the same position a lot in syzygy/tbproblem.cpp you can cut the code st-> previous only one maybe help the endgame better than old code. I hope you understand what I mean.

On Thu, 13 Feb 2020, 00:02 Ada Joule, notifications@github.com wrote:

By the way, can both players count at the same time? No. The rule explicitly says only the disadvantaged player counts.

Can the opponent of the counting player claim a draw? I'm not sure on this one, but I'm convinced it's a yes. I have some tournament rules statement, but there are different takes on this. I'll just put the sources here along with what they say. Sources (Thai): "While counting, the counting side is considered to be offering draw the entire time." http://bgsthai.com/2018/04/30/howtoplay/ "If the disadvantaged player sees that they can win, they must stop counting. If they don't, their opponent may claim a draw." http://www.lovemakrukthai.com/wp-content/uploads/2012/08/คู่มือกติกาหมากรุกสำหรับผู้เข้าแข่งขัน-ทุกสนาม.pdf "If the disadvantaged player sees that they can win, they must stop counting. If they don't, their win will be adjudicated as a draw." http://www.lovemakrukthai.com/wp-content/uploads/2012/10/กติกาการแข่งขันหมากรุกไทย-สมาคมกีฬาไทยในพระบรมราชูปถัมภ์.pdf

Could the advantaged player start counting to prevent his opponent from doing so? That's the abuse I'm concerned about. This usually doesn't arise in OTB play since an arbiter (or spectator in casual play) can verify which side is having advantage and act accordingly.

If you ask my opinion, I think implementing "opponent of the counting side may claim a draw" and "checkmate by the counting side is a draw" is the most elegant solution. This also means checkmate in the same turn as stopping the count is also a draw.

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/ianfab/Fairy-Stockfish/issues/76?email_source=notifications&email_token=AJ6EZFHESDWPATW3P36JHMDRCSEZRA5CNFSM4KS6AZK2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOELS3QNA#issuecomment-585480244, or unsubscribe https://github.com/notifications/unsubscribe-auth/AJ6EZFGLXBBSYLZPKUKDGE3RCSEZRANCNFSM4KS6AZKQ .

ianfab commented 4 years ago

Thanks, much clearer now. Identifying which side has the advantage however still seems like a difficult task:

Or did you mean to just ignore these questions and allow both players to count since they can not abuse it due to the right to claim a draw?

Fulmene commented 4 years ago

Yeah I meant just ignore all those questions and let both players start the counting. If the advantaged player tries to count then the other player will claim a draw immediately. Likewise, if the game turns around and the counting player doesn't stop counting then the draw may also be claimed.

Fulmene commented 4 years ago

I'll answer your questions anyway though. Even if they don't matter now, this knowledge might be of use in the future. In most of these answers, I'll tell you what would be done "in practice" since starting the count is subject to player's choice.

Do we simplify identify the weaker side by counting material?

The Law of Thai Chess (the first source in my previous comment) actually has a guideline for determining which side has the advantage by counting material. The score for each piece is rook = 5, knight = 3, khon = 2.6, met = 1.7, pawn = 1. The side with less total score is the disadvantaged side.

What if one side is down material but will win material by force soon. Which side may start counting?

In this case, the side that is down material usually won't start counting in the first place. Or, if they do start the count, they will just stop once they gain the advantage.

And what if the position is perfectly equal?

The players will either agree to draw or wait for mistake from the other side. No one will start counting in this case.

And what if the stronger side makes a mistake and gets a lost position? Does the stronger side have to stop counting?

They will stop counting, or risk the other player claiming draw.

ianfab commented 4 years ago

Makes sense. Now we need to find a way to describe the situation where no player is counting although it would be possible. In order to make sure that the engine knows that counting could start at any time, it would perhaps make sense to just freeze the counting at 128 0 and only let it start incrementing the ply count as soon as it receives a signal to start counting. As mentioned, the signal perhaps should be a UCI option. It could either be a button type to toggle counting or a boolean option to switch on or off, but perhaps the latter is more clear. In case of engine-engine matches the option could always remain true, while for human matches it would be false by default and only set to true if a player requests counting.

Counting by the pieces' honor rule should be mandatory, right?

Fulmene commented 4 years ago

In that case, how would we handle draw on checkmate in engine vs engine? Perhaps, if we want the exact same result as the current version in engine vs engine games, we could introduce a "draw on checkmate" variable to be set to the counting side when the counting starts in a human game.

I think a button type option will make more sense. There might be more things that need to be set when the counting stops, namely resetting the game state to "no counting" and maybe the aforementioned draw on checkmate variable.

Then there might also be human vs engine games we need to worry about.

The piece's honour rule is mandatory, yes.

ianfab commented 4 years ago

The choice of the UCI option type purely is an interface decision, it does not have any impact on the actions that can be invoked when the option is set.

Since setting options should be idempotent, only the boolean option makes sense.

Fulmene commented 4 years ago

Okay. I'm not really familiar with UCI.

I agree now that boolean option is the only thing that makes sense here.

ianfab commented 4 years ago

Actually this solution does not work either way, since in the UCI protocol the position is set using a start FEN plus a list of moves, so the engine can not know at which point of the move list the counting was enabled/started.

thaichessswinboard commented 4 years ago

Or another way can you make engine know about count 8 when have 2 rooks minus pieces on board by not captured the last piece of weakside it will help engine know to win the games in case of 2 rooks and case 2 silver's engine strong Side must not capture the last pieces of weakside it will help engine more strong because that 2 case it hard case of makruk if engine know that rules it will strong. I hope you understand what I mean. On Wed, 19 Feb 2020, 20:14 Fabian Fichter, notifications@github.com wrote:

Actually this solution does not work either way, since in the UCI protocol the position is set using a start FEN plus a list of moves, so the engine can not know at which point of the move list the counting was enabled/started.

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/ianfab/Fairy-Stockfish/issues/76?email_source=notifications&email_token=AJ6EZFHUXPC2UG2X7FITJD3RDWHJ5A5CNFSM4KS6AZK2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEMJK3RI#issuecomment-588426693, or unsubscribe https://github.com/notifications/unsubscribe-auth/AJ6EZFHSBSCSNDH77KSP7ZTRDWHJ5ANCNFSM4KS6AZKQ .

Fulmene commented 4 years ago

So there's no other way to change the game state without a move? I suppose incorporating start/stop counting into the move is another way to go, but that might introduce a whole lot of compatibility issues.

ianfab commented 4 years ago

There still are other options, while encoding it with a move to me is not really an option. It would not really be a problem to allow them as kind of pseudo-moves in the position command, but then it would only work for the CLI but not for the pyffish python wrapper, which is essential for the feature to be used on pychess.

Some alternatives I was thinking of are:

  1. Add an option to set a move count at which counting was started. In this way it can just start counting from the point in the move list where this move count was reached. The disadvantage would be that we then basically encode board state in an option and the option would need to be reset when setting up a position of a new game.
  2. Add one option to enable manual board counting and a second option to set/overwrite the current board count after setting up a position.
  3. For Makruk always communicate the FEN instead of the move list from the starting position. This however is not really an option as it has many implications starting with repetition detection, etc.
Fulmene commented 4 years ago

Why would these pseudo-moves not work with pyffish? Also how does pseudo-move work and has it been used in any other variant?

I also don't understand the alternatives 1 and 2 you thought of. Could you elaborate further? How are they different from what we talked about earlier?

ianfab commented 4 years ago

The point is that they can not be real moves, since moves need to change the side to move in SF. Therefore, they could only be some kind of fake moves that are filtered out when parsing the move list but could trigger some side effect like updating the count. However, pyffish does not work on the CLI level so this would not have any effect on it, and the same logic would perhaps need to be duplicated for it. All of that sounds very fragile, so I do not really want to explore this idea further.

Both suggestions try to solve the problem of knowing the time when counting was started. It is important to keep in mind that in UCI move lists are sent from scratch after every move on the board (since the protocol is stateless), so the engine receives something like position fen startFEN moves move1 move2 move3 ..., not just the last move compared to the previous position. Therefore if the engine only knows whether counting was enabled or not, it can not know whether it was after move1, move2, or later.

  1. Let's say you tell the engine via a UCI option that counting was or will be started at move 51 (probably in half-moves). When it then parses the move list it checks on every move whether move 51 is reached and if so it starts counting and continues counting when parsing the subsequent moves. A special value like 0 or an additional option could indicate that counting is disabled.
  2. After sending the position ... command another command could be sent to overwrite the count, e.g., via a UCI option value, since the engine might have started to count earlier.

Another possibility might be to break the statelessness of the position command and re-use the count from the previous position command. I have not thought about this yet.

Fulmene commented 4 years ago

I like option 2 more. It has the disadvantage that the count needs to be stored in the GUI, but otherwise look cleaner than the other option. Option 1 encoding the game state to options doesn't look good to me, but it's easier on the GUI side so I'm not ruling it out entirely yet.

Onto the details of implementation. I think we might not even need an option for manual counting since receiving an overwrite implies that the GUI supports manual counting already. I still have some concerns over how it would work in human vs engine games though.

Breaking the statelessness of the position command looks dangerous. I don't think that's an option at all.

ianfab commented 4 years ago

I agree. I considered the option for manual counting to handle the case when counting is not started although it could be. However, the engine can still assume in its search that counting will be started right after that position, so just resetting the count to 0 by the overwrite command should also work.

Thinking about it again, Fairy-Stockfish might not even need to have this feature, since we probably anyway neglect this detail for analysis. It is pyffish that needs it, and pyffish could perhaps just directly manipulate the position on its own.

For human vs engine play I am not sure yet how to handle it. The most straightforward might be to either always or never let the engine count (if always, then draw claim based on that should be disabled against engine). The solution for that might also be relevant for the decision on the implementation.

Fulmene commented 4 years ago

If no overwrite is sent, it will just retain the current behaviour, right? That's what I was thinking of when I read both options.

As I understand, Pychess is quite a special case, using Fairy-Stockfish itself (via pyffish) as a chess server. It feels weird having some features in pyffish and not in FairySF though, but you're in a better position to say things about this. I still think we should implement it in Fairy-Stockfish to better support anyone else trying to use it without python.

Fulmene commented 4 years ago

I'm not sure how to handle human vs engine either. It doesn't seem to be something the engine can "choose" to do based on the board's situation like moves so I'm out of option at the moment.

ianfab commented 4 years ago

The overwrite solution is not very practicable for usage in GUIs (unless they would explicitly support it), since you would need to manually set this option after every half-move in the counting phase, not only when you start/stop counting. Therefore, if we take this solution then support in Fairy-Stockfish is not really relevant in my opinion.

Fulmene commented 4 years ago

I'm going to summarise the works here.

Pyffish:

Pychess:

For human vs engine I'd say retaining the current behaviour would be most convenient.

ianfab commented 4 years ago

The methods of pyffish where counting is relevant should be get_fen and is_optional_game_end. However, looking at the pychess code I do not see a good way how this can be implemented by delegating the logic to pyffish via FairyBoard, since it still needs to handle optional counting explicitly.