Xiangqi: perpetual chase question

Discussion of chess software programming and technical issues.

Moderators: hgm, Rebel, chrisw

User avatar
hgm
Posts: 27790
Joined: Fri Mar 10, 2006 10:06 am
Location: Amsterdam
Full name: H G Muller

Xiangqi: perpetual chase question

Post by hgm »

I am in doubt about the priority of the rule that it is allowed to perpetually offer exchange of equal pieces. One way to look at it is that the possibility to exchange is as good as being protected, i.e. the piece is capable of self-defence, and initiating the exchange is like a 'pre-emptive' recapture. In that interpretation the following perpetual would be a draw:

[d]3k2e2/9/4e4/6o2/4po1n1/2P6/P4NP2/5F3/4F4/4KO3 w
1.Hd4 Cfg5 2.Hf3 Cf5

This because 1. Hd4 is not a chase, but an offer to exchange. Had we played 1.Hd2 instead, this would be obvious, as we would have one offer to exchange plus one chase, which is allowed. But with 1.Hd4 the Horse also attacks the the Cannon. So is this still an offer to exchange, disarming the Horse attack just like a protector of f5 would have disarmed it? Or should this be considered a Horse chasing an unprotected Cannon, disregarding the possibilty for self-defence of the Cannon through 1... Cf5xf0?
User avatar
Evert
Posts: 2929
Joined: Sat Jan 22, 2011 12:42 am
Location: NL

Re: Xiangqi: perpetual chase question

Post by Evert »

Chase rules are a convoluted mess, because they are largely defined by precedent rather than a clear-cut rule. At least in my opinion.

With that caveat, the fact that there exists a SEE-neutral exchange after Hd4 says, to me, that this is indeed not a chase.
User avatar
phhnguyen
Posts: 1434
Joined: Wed Apr 21, 2010 4:58 am
Location: Australia
Full name: Nguyen Hong Pham

Re: Xiangqi: perpetual chase question

Post by phhnguyen »

hgm wrote: Fri Feb 01, 2019 7:04 pm I am in doubt about the priority of the rule that it is allowed to perpetually offer exchange of equal pieces. One way to look at it is that the possibility to exchange is as good as being protected, i.e. the piece is capable of self-defence, and initiating the exchange is like a 'pre-emptive' recapture. In that interpretation the following perpetual would be a draw:

[d]3k2e2/9/4e4/6o2/4po1n1/2P6/P4NP2/5F3/4F4/4KO3 w
Very strange FEN format for me, my program did not understand the piece notation 'o' ;)
hgm wrote: 1.Hd4 Cfg5 2.Hf3 Cf5

This because 1. Hd4 is not a chase, but an offer to exchange. Had we played 1.Hd2 instead, this would be obvious, as we would have one offer to exchange plus one chase, which is allowed. But with 1.Hd4 the Horse also attacks the the Cannon. So is this still an offer to exchange, disarming the Horse attack just like a protector of f5 would have disarmed it? Or should this be considered a Horse chasing an unprotected Cannon, disregarding the possibilty for self-defence of the Cannon through 1... Cf5xf0?
It is not a chase, since the Cannon is protected sometimes. One is perpetual check or chase only if it does it continuously, non-stop. Any pause, stopping in the sequence of moves won't be. Attacking a protected piece is a pause. Exchange offer is a pause too. Your example is too easy to rule ;)

Take care that Rook cannot be considered as being protected under attacking of Cannon/Horse. If you replace that Cannon by a Rook, the Horse becomes a chaser.

That is why my program rules games in two separating steps, the first one is to detect continuously chasing without taking care the relationship between attackers - victims, in this case the Horse is doing that but not that black Cannon since it is not continuously chasing the white Cannon (in one move black Cannon offered the exchange but not white Cannon). The second step is to detect if the chase is allowed. In this case it is allowed since the Cannon was protected sometimes. I don't have to worry about priority of chasing / exchange offer too since it rules base one finding any legal move as a pause. The first step is similar but not the second one for the Rook case.
https://banksiagui.com
The most features chess GUI, based on opensource Banksia - the chess tournament manager
User avatar
phhnguyen
Posts: 1434
Joined: Wed Apr 21, 2010 4:58 am
Location: Australia
Full name: Nguyen Hong Pham

Re: Xiangqi: perpetual chase question

Post by phhnguyen »

phhnguyen wrote: Tue Feb 05, 2019 3:40 am That is why my program rules games in two separating steps, the first one is to detect continuously chasing without taking care the relationship between attackers - victims, in this case the Horse is doing that but not that black Cannon since it is not continuously chasing the white Cannon (in one move black Cannon offered the exchange but not white Cannon). The second step is to detect if the chase is allowed. In this case it is allowed since the Cannon was protected sometimes. I don't have to worry about priority of chasing / exchange offer too since it rules base one finding any legal move as a pause. The first step is similar but not the second one for the Rook case.
Correct a bit:
In the first step my program detected: white Horse and Cannon are chasing black Cannon, but black Cannot is not chasing any white piece.
In the second step it checks:
- The first move: Horse is chasing => not allowed but two Cannons are an exchanged => allowed. I think it is an ambiguous here, we may rule both by OR or AND. My program did not allow since chasing is stronger.
- Second move: Cannon is protected => allowed => clear draw BTW
https://banksiagui.com
The most features chess GUI, based on opensource Banksia - the chess tournament manager
User avatar
hgm
Posts: 27790
Joined: Fri Mar 10, 2006 10:06 am
Location: Amsterdam
Full name: H G Muller

Re: Xiangqi: perpetual chase question

Post by hgm »

OK, sorry, my mistake. It was not my intention that the black Cannon would ever be protected. So imagine the Elephant on e7 is not there at all. From your second posting I understand that for the 1.Hd4, where the Horse chases the Cannon and at the same time the Cannon offers exchange, you would not judge the exchange offer a valid 'excuse' for the Horse's chase, although it does excuse the Cannon's chase. (I think HaQiKi D would judge likewise.) This was exactly what my question was about.

You mention that this is is an ambiguity. Was the choice to make the chase prevail over the offer to exchange in your program an arbitrary choice, or is there an indication that this indeed must be the true rule? Perhaps the following argument can be made that the possibility to exchange should not be considered as good as being protected (and that the Horse is thus indeed chasing here): there could also exist a static possibility to exchange

[d]r2ko1e1O/9/4e4/9/4P1N2/9/8P/9/4F4/3FK3O w
1.Hf7 Cf9 2.Hh8 Ce9 3.Hf7 ...

Here black can at any time exchange Cannons (but obviously would not want to, as this loses him a Rook). Nowhere the rules ever mention that such a static possibility to exchange would count as protection, and thus allow the new attack by the Horse. So I think everyone would agree that this is a forbidden chase of a Cannon by a Horse. (The King is a false protector when the Cannon is on e9 because there is a second attacker, making it illegal for the King to recapture.) If a static possibility to exchange is no excuse for an active chase by another piece, there seems little reason to consider a newly offered exchange such an excuse.

Now that you mention implementation:

My reason for looking at this problem again is that I am trying to fix the Xiangqi implementation in Jocly. I was wondering how I could do this without consuming an unacceptably large amount of CPU time. My thinking also converged on a 2-stage process: first determine which pieces receive new pseudo-legal attacks on every move of the loop, in the hope that this would leave only very few pieces on which more complex testing (for legality, protection and exchange) has to be done in stage 2. The new attacks can be selectively generated (rather than just running the existing move generator for the side not to move). This is still pretty complex, though: new attacks can be 'direct' (by the moving piece from its new location), 'discovered' (R, C, H or E over the from-square), 'activated' (C over the to-square), and 'unpinning' (the moved piece lands on pin ray). The latter case is relatively rare, and can be cheaply ruled out by testing whether the to-square is orthogonally aligned with the friendly King (14 of the 90 squares, as it must also not be on an edge). But if that happens to be the case a lot more work has to be done, and in case of a Cannon pin it could even revive two additional pieces. The testing for discovered attacks can also start with testing for orthogonal alignment of the R, C, H in the piece list (the H only on adjacent squares); discovering E has only to be tested for on 8 squares of the board, in which case the Elephant can only be in two locations diagonally adjacent to that. At any move of the loop it can be tested how many of the pieces that are still chase candidates receive new attacks (and those that dont cease to be chase candidates). If this number ever drops to zero, stage 1 can be aborted, and stage 2 skipped.

In stage 2 all remaining chase candidates would then have to be checked on every move for
1) the possibility to capture their chaser, (i.e. equal type), and whether this is legal
2) whether they are protected against any of the new attacks, and whether those recaptures are legal
3) whether the attacks on them were legal in the first place
For C/H on R step 2 can be skipped. I thought it would be best to do the tests in that order; (3) is relatively cheap, but it has only a low chance to decide the matter, (most pseudo-legal moves will also be legal), so the other tests would have to be done anyway. It is very cheap to determine if (1) can aply (just comparing the piece types of attacker and chase candidate), and if it can, it usually will (again because only a minority of moves is illegal, although you also have to test for Horse blocking here). So I put that first (and then hope there was no second attacker, like in the diagram of the initial posting). Doing (2) is in general quite time consuming, but true protection will be pretty common. I am not sure whether it would be better to do (3) before (2); even if it only rarely decides the matter, it would save a lot of work in (2) when it occasionally does.

P.S.: sorry about the FEN. The current JavaScript diagram generator in this forum uses a 1-letter code for the pieces, and A and C were already in use for the Archbishop and Chancellor of Capablanca Chess. So I used the 1-letter code that was used by (very) old WinBoard versions, with O for cannOn, and F for Ferz (which moves the same as the Xiangqi Advisor). Quite inconvenient, actually. Especially since XBoard (from which the piece images are taken) now supports 66 piece types, and the alphabet has only 26 letters. So 1-letter coding is not viable anyway. It is still on my to-do list to fix that. I have another FEN generator (doing direct SVG rendering) on my own website, which allows 'dressed letters' (= letter + punctuation sign, such as X', X`, X~ and X!) as piece ID. The problem is not only to get enough different IDs, but also to assign those in such a way that they can be easily remembered. So in that other generator I used X~ to indicate 'knighted' pieces (because ~ looks somewhat like N), so that B~ and R~ can be used for Archbishop and Chancellor, and the A and C become available for other pieces. Likewise X' and X` would indicate 'wazired' and 'ferzed' pieces. Other contenders for A and C are the Alibaba and the Camel, though. Perhaps I should make the meaning of the IDs board-size dependent, and interpret A and C as Adviser and Cannon on 9x10 boards. (I already adapt the square shading in that case...)
User avatar
phhnguyen
Posts: 1434
Joined: Wed Apr 21, 2010 4:58 am
Location: Australia
Full name: Nguyen Hong Pham

Re: Xiangqi: perpetual chase question

Post by phhnguyen »

hgm wrote: Tue Feb 05, 2019 10:49 am OK, sorry, my mistake. It was not my intention that the black Cannon would ever be protected. So imagine the Elephant on e7 is not there at all. From your second posting I understand that for the 1.Hd4, where the Horse chases the Cannon and at the same time the Cannon offers exchange, you would not judge the exchange offer a valid 'excuse' for the Horse's chase, although it does excuse the Cannon's chase. (I think HaQiKi D would judge likewise.) This was exactly what my question was about.

You mention that this is is an ambiguity. Was the choice to make the chase prevail over the offer to exchange in your program an arbitrary choice, or is there an indication that this indeed must be the true rule? Perhaps the following argument can be made that the possibility to exchange should not be considered as good as being protected (and that the Horse is thus indeed chasing here): there could also exist a static possibility to exchange

[d]r2ko1e1O/9/4e4/9/4P1N2/9/8P/9/4F4/3FK3O w
1.Hf7 Cf9 2.Hh8 Ce9 3.Hf7 ...

Here black can at any time exchange Cannons (but obviously would not want to, as this loses him a Rook). Nowhere the rules ever mention that such a static possibility to exchange would count as protection, and thus allow the new attack by the Horse. So I think everyone would agree that this is a forbidden chase of a Cannon by a Horse. (The King is a false protector when the Cannon is on e9 because there is a second attacker, making it illegal for the King to recapture.) If a static possibility to exchange is no excuse for an active chase by another piece, there seems little reason to consider a newly offered exchange such an excuse.
I agreed, it is a forbidden chase by the Horse. Static attacking should be ignored. We count only attacks which one side tries to escape and other side tries to set back. In my algorithms, I used the operator - (subtraction) between two sets of attacks to remove all static attacks.
hgm wrote: Tue Feb 05, 2019 10:49 am
Now that you mention implementation:

My reason for looking at this problem again is that I am trying to fix the Xiangqi implementation in Jocly. I was wondering how I could do this without consuming an unacceptably large amount of CPU time. My thinking also converged on a 2-stage process: first determine which pieces receive new pseudo-legal attacks on every move of the loop, in the hope that this would leave only very few pieces on which more complex testing (for legality, protection and exchange) has to be done in stage 2. The new attacks can be selectively generated (rather than just running the existing move generator for the side not to move). This is still pretty complex, though: new attacks can be 'direct' (by the moving piece from its new location), 'discovered' (R, C, H or E over the from-square), 'activated' (C over the to-square), and 'unpinning' (the moved piece lands on pin ray). The latter case is relatively rare, and can be cheaply ruled out by testing whether the to-square is orthogonally aligned with the friendly King (14 of the 90 squares, as it must also not be on an edge). But if that happens to be the case a lot more work has to be done, and in case of a Cannon pin it could even revive two additional pieces. The testing for discovered attacks can also start with testing for orthogonal alignment of the R, C, H in the piece list (the H only on adjacent squares); discovering E has only to be tested for on 8 squares of the board, in which case the Elephant can only be in two locations diagonally adjacent to that. At any move of the loop it can be tested how many of the pieces that are still chase candidates receive new attacks (and those that dont cease to be chase candidates). If this number ever drops to zero, stage 1 can be aborted, and stage 2 skipped.

In stage 2 all remaining chase candidates would then have to be checked on every move for
1) the possibility to capture their chaser, (i.e. equal type), and whether this is legal
2) whether they are protected against any of the new attacks, and whether those recaptures are legal
3) whether the attacks on them were legal in the first place
For C/H on R step 2 can be skipped. I thought it would be best to do the tests in that order; (3) is relatively cheap, but it has only a low chance to decide the matter, (most pseudo-legal moves will also be legal), so the other tests would have to be done anyway. It is very cheap to determine if (1) can aply (just comparing the piece types of attacker and chase candidate), and if it can, it usually will (again because only a minority of moves is illegal, although you also have to test for Horse blocking here). So I put that first (and then hope there was no second attacker, like in the diagram of the initial posting). Doing (2) is in general quite time consuming, but true protection will be pretty common. I am not sure whether it would be better to do (3) before (2); even if it only rarely decides the matter, it would save a lot of work in (2) when it occasionally does.
I am used to worry about the performance of Xq perpetual check/chase algorithms. However after installing a full one for my engine (Felicity - the one you have played against last year) the statistics says only 0.5% search nodes are perpetual checks or chases. Too small to affect the performance of an engine. It should be the same for a GUI too. I think it is better to focus on correctness and simple, readable code.
https://banksiagui.com
The most features chess GUI, based on opensource Banksia - the chess tournament manager
User avatar
hgm
Posts: 27790
Joined: Fri Mar 10, 2006 10:06 am
Location: Amsterdam
Full name: H G Muller

Re: Xiangqi: perpetual chase question

Post by hgm »

phhnguyen wrote: Wed Feb 06, 2019 1:48 pmI agreed, it is a forbidden chase by the Horse. Static attacking should be ignored. We count only attacks which one side tries to escape and other side tries to set back. In my algorithms, I used the operator - (subtraction) between two sets of attacks to remove all static attacks.
I was not worried so much about the static attack (of white Cannon on black Cannon), as well as that the chased side always has the opportunity to trade (black Cannon x white Cannon) here.