Comments/Ratings for a Single Item
Turns out my code was causing bugs with Gote's Whale highlights. So I removed the Anti-Lion-trading code and cleaned up extraneous code in my applet.
It would be nice if we could add a gray highlight for the illegal Lion trading moves for the Chu diagram on this page, but I am not sure how to go about doing that.
It would be nice if we could add a gray highlight for the illegal Lion trading moves for the Chu diagram on this page, but I am not sure how to go about doing that.
If it was easy I would already have done it...
The AI already pays attention to the Lion-capture rules and other legality issues, so the easiest way is to reuse the AI components. When using the NewClick() move entry routine the entered moves are already performed by the same routine NewMakeMove() as that the AI uses.
The AI uses a recursive routine Search(), which uses the move generator GenAll() to create a move list for the side that is on move. It then loops through the moves in that list to find the best/a satifactory one. To do that it first evaluates the direct gain of the move, through a routine ScoreMove(). This calculates the value of what the moves captures, checks if it destroys opponent or own royalty, and adds some info to the move that was not in the 'raw' moves coming from the move generator. (Such as identifying pieces that have to be burned, and remembering the original occupants of mutated squares, identifying the pieces that are made temporary royal or iron by the move and adapt the score for moves that capture those.) After 'cooking' the move with ScoreMove() it can be applied to the current position by NewMakeMove(), and later taken back with UnMake();
Both GenAll() and ScoreMove() make use of the preceding ply, e.g. to generate e.p. captures, and applying trading restrictions.
Currently NewClick() uses GenAll() to create the list of pseudo-legal moves, and then uses mouse clicks to eliminate those from the list that would not be indicated by those, until a single move is left. This raw move is then cooked by ScoreMove(), and performed by NewMakeMove(). As long as there are still multiple moves in the list, the squares corresponding to the next click these need to be selected will be highlighted.
To do fully legal highlighting we would have to make every move, and then judge the position based on the possible replies in the resulting position. Not just the one that is finally selected. That means that ScoreMove() will have to be applied to each of the moves. So the call to it should be moved to within the loop that selects the moves to be highlighted. And then there should be a NewMakeMove(), GenAll(), {judge}, UnMake() sequence in that loop as well, where the 'judge' part would apply ScoreMove() to all replies, to see if there is an instant win amongst those (which then would make the move to be highlighted illegal). If there is the grey cross should be chosen as highlight marker.
Yeah...I think it's better to just leave it as-is, except maybe passing the full move to the AI, rather than just the origin and destination...but that's a topic for another day.
I think I managed it! There were all kinds of problems, because ScoreMove() only work if the AI tables (such as piece values) are initialized. Which only happened when you actually started playing against it. Otherwise it returns undefined results when pieces get captured. And it was not only that the tables needed to be defined; they actually had to contain the correct values. Otherwise the bridge-capture rule could not be correctly applied.
But I think it works now: pseudo-legal moves that the AI would consider illegal are now highlighted with a grey cross. This applies to intrinsically illegal moves (blowing up your own royal, capturing an iron piece or making a counter-strike) as well as to moves that can be punished in the reply (exposing your royal to capture, or capturing a protected Lion).
In the Chu-Shogi Diagram there are no restrictions on royal exposure, as it specifies royal=100, but as far as I tested the Lion-capture rules are now correctly indicated with the highlights.
You got most of it. However, I did find a few bugs involving the counterStrike highlights.
In this game, after the Soaring Eagle takes the Queen and then the Lion, the gray highlights are not displayed at all (General Case: double capture that captures non-Lion piece and then Lion):
1. e5 h8 2. De4 Dh9 3. Df5 Dg8 4. Dxf9+ Dxg4+ 5. +De8 +Dh5 6. Qg4 Qf9 7. +Dxf9xg10
In this game, the counter-strike highlight doesn't happen for all the Lions, but only for the piece type that was just captured:
1. f5 g8 2. Of4 Og9 3. Of6 Og7 4. Of8 Og5 5. Og9+ Of4+ 6. Ng5 Nf8 7. Ng7 Nf6 8. Qxf4 or fxf5
In this game, the counter-strike highlight highlights don't show at all for piece that have the option of proomoting after capturing a Lion:
1. f5 g8 2. Of4 Og9 3. Of6 Og7 4. Of8 Og5 5. Ne5 Nh8 6. Og9 Of4 7. j5 c8 8. Hk5 Hb8 9. h5 e8 10. Dh4 De9 11. Dg5 Df8 12. Dh6 De7 13. Di6 Dd7 14. Dxi8 Dxd5 15. Dxi9 Dxd4 16. Hxh8
Otherwise, thank you so much! This saved me a heck of a lot of time.
Ummm... I intentionally implemented the counterStrike ban to declare a particular type 'temporary iron', rather than just any type that has the counterStrike property. This to allow multiple types to have it. This appears to backfire in case Ln and +Kn are defined as different types. The other cases I will examine tomorrow.
We should see here what the AI does, so we are now debugging the AI...
There are several ways to cure this. The simplest would be to switch to making all types with the counterStrike property temporary iron after one of those is captured by a piece without this property. A more subtle (and more versatile) approach would be to assign piece types to 'groups', and make all types in the group that was captured temporary iron. This could be done by introducing a parameter group=N, which would then put pieces of that type in group N. (With as default every type being in a group of its own, so that in Chu Shogi only the +Kn would have to be assigned the type number of the Lion.)
I could also use the counterStrike parameter itself for this, giving it a different meaning when used after pieces have been defined: currently counterStrike=N would endow type N with the property, but after a piece definition it could assign the preceding type to group N. This method is already used for antiTrade (which defines relative ironhood), so it might be the best solution.
All problems you pointed out should be solved now. (Thanks for finding those!)
The problem with promotable pieces was caused by promotion scoring to take place after royalty checking in ScoreMove; because of that the 'immediate loss' score of -15000 was increased by the promotion gain, and no longer recognized as such. It should have returned the losing score immediately when it was found. (This should not have hurt the AI very much, as the score would still be extremely low, so that it would only count on the forbidden move in positions where getting checkmated was the only alternative.)
I implemented type groups for counter-striking, assigned by counterStike=N behind a piece type that should be added to another group N than its own type number (and added that behind the Kirin to map it to the Lion's type, N = 20).
The problem that the final victim of a double capture was not noticed as having to be declared temporary iron, is solved in a fragile way: ScoreMove was adding the anti-trade codes of all victims, and (if one of those was subject to a counter-strike rule) would then check the type group of the last-handled victim (the locust victim) to see if it belongs to the temporary iron type group. I now added code to test whether this victim actually has the counter-strike property; if not, the other victim must have been responsible, and it substitutes the replacement victim for it before doing the type-group test. This solves the Chu-Shogi case, but could fail if there are more than two victims, if there are two locust victims, or if both victims have the counter-strike property, but belong to a different type group. (And there is currently no method for declaring more than one type-group temporary iron.)
I also fixed the moving into check highlighting; I had forgotten to call CountRoyals() in the betzaNew.js here on CVP.
All the cases I mentioned are fixed. I did find a couple more bugs though:
In this game, after the Soaring Eagle takes the Lion and then moves to a non-Lion square, the counter-strike highlights do not appear.
1. e5 h8 2. De4 Dh9 3. Df5 Dg8 4. Dxf9+ Dxg4+ 5. Gd2 Gi11 6. Ke1 Kh12 7. +Dg8 +Df5 8. +Dh9 +De4 9. +Dxg10xf11 or +Dxg10xh9
However, if Sente makes a random move (i.e. advancing the left edge Pawn w/ 9. a5) and Gote tries the same thing w/ 9... +Dxf3xg2 or +Dxf3xe4, the counter-strike highlights are displayed correctly.
In this game, after a Kirin takes a Lion and promotes to Lion, the counter-strike highlights erroneously appear on the newly promoted Lion:
1. Ne5 Nh8 2. f5 g8 3. Of4 Og9 4. Of6 Og7 5. Of8 Og5 6. Og9 Of4 7. Oxh8+
In this game, after moving the Lions adjacent to each other, the bridge-capture highlights still show even though the Lions are adjacent:
1. Ng5 Ng8 2. Ni6 Ni7
OK, I solved the 'promoting Kirin' bug. This was due to the AI comparing the capture square with the origin of the previous move, rather than the destination.
The adjacent case is partially due to a 'calculated risk': the exemption of adjacent Lions from the protection rule is motivated by the fact that you would never want to capture a protected Lion by replacement if you could capture it throug hit & run. Making the same exception for a piece not capable of locust capture makes no sense. To make the rule also useful for such pieces, I dropped the adjacency condition from the implementation of the rule in the Interactive Diagram. The AI might erroneously believe it was illegal, but it would virtually never want to play it anyway. And when the highlights were still only pseudo-legal, it would not make any difference there either.
The other part of the problem might be solvable in the highlighting: even though it thinks the replacement capture is illegal, it thinks locust capture is allowed, so there also is a cyan start highlight on that square. (Which overrules the red triangle for the direct capture because of the order of these in the XBetza spec.) I guess I should in any case refrain from overruling the star marker by a cross. The cross then would still appear in the highlights for the second leg, for the click that would select termination after the first leg, though. But that is the move you would almost never want to play, so this might be excusable. After all, moving the King in check is also highlighted by a cross now, and that is not strictly forbidden in Chu Shogi either. So the meaning of the cross should be taken a bit liberally, as 'not recommended', rather than strictly forbidden.
The third case was due to forgetting to strip off the color bit when looking up the anti-trade properties when testing whether the replacement victim had to be replaced by the locust victim when setting the temp-iron type.
Looks like everything is fixed as far as highlights go (The important part is that all illegal Lion-trading moves are highlighted as such). I have copied the updated betzaNew code to my Chu Shogi Applet.
[Edit] I added the line morph=| after the Pawn definition to allow Pawns to promote on the last rank on a non-capture.
There's a visual bug with CountRoyals() where it counts a piece with the protected/counterStrike property as royal if there are no true royals of the same color on the board. This probably has something to do with how values in the royalness array are interpreted within the function.
As per your recommendations, I did some testing with the AI, and I encountered a bug where the counter-strike rule is not being followed by the AI at all.
Case 1: Normal pieces
1. Nh5 Ne8 2. Ni7 Nd6 3. Ixd6
Responds with 3... Ixi7
Case 2-5: Multi-movers
1. e5 h8 2. De4 Dh9 3. Df5 Dg8 4. Dxf9+ Dxg4+ 5. +Dg8 +Df5 6. +Dh9 +De4 7. Gd2 Gi11 8. Ke1 Kh12
Case 2: Normal move
9. +Dxg10
Responds with 9... +Dxf3xe2
Case 3: Igui
9. +Dxg10xh9
Responds with 9... +Dxf3xg2
Case 4: Double capture, Lion captured on first move
9. +Dxg10xf11
Responds with 9... +Dxf3xg2
Case 5: Double capture, Lion captured on second move
9. +Dxi8 +Dxd5 10. He4 Hh9 11. +Dxh9xg10
Responds with 11... +Dxe4xf3
Case 6: Capturing two Lions
1. f5 g8 2. Of4 Og9 3. Of6 Og7 4. Of8 Og5 5. Og9+ Of4+ 6. +Og7 +Of6 7. +Og6 +Of7 8. +Of4 +Og9 9. h5 e8 10. Hxd8 Hxi5 11. He9+ Hh4+ 12. +Hf8 +Hg5 13. +Hxg8 +Hxf5 14. Gd2 Gi11 15. Ke1 Kh12 16. +Hxg9xg10
Responds with 16... +Hxf4xf3
Case 7: Kirin promotion exception
1. f5 g8 2. Of4 Og9 3. Of6 Og7 4. Of8 Og5 5. Ne5 Nh8 6. Og9 Of4 7. Oxh8+
Responds with 7... Oxe5+
It appears that betzaNew.js never passed the last game move to the AI. The code I had added to pass a dummy move in case no game move was played yet erroneously always passed the dummy move (because the moves are JavaScript objects rather than arrays, and I tested for the latter). So the AI would also not have been able to perform e.p. capture.
Should be fixed now.
Thanks for fixing this! Now the ID's AI plays Chu Shogi properly.
I did notice a visual bug with CountRoyals() where it counts a piece with the protected/counterStrike property as royal if there are no true royals of the same color on the board. This probably has something to do with how values in the royalness array are interpreted within the function.
Not a big deal for normal diagrams, but may affect highlights of diagrams where one side has no royals, like those of tsume problems. Fixing it is not really a high priority for me, but I figured I should let you know anyway.
Actually every move should be marked as illegal for a player that has no royal in a game where royals are defined. It is just that the absence of royalty is only tested when a piece with special (royalty, baring, anti-trading) properties is captured, as the AI assumes royalty still exists before the move, or the search branch would already have been terminated earlier. So it only tests it when it could have changed.
I guess the current AI would choke on tsume positions without King.
[Edit] For the purpose of highlighting the legality test now assumes a royaltyCount of 1 in the current position when in reality royaltyCount <= 0. In terms of scoring this fakes a single royal for the side that has none.
Actually every move should be marked as illegal for a player that has no royal in a game where royals are defined. It is just that the absence of royalty is only tested when a piece with special (royalty, baring, anti-trading) properties is captured, as the AI assumes royalty still exists before the move, or the search branch would already have been terminated earlier. So it only tests it when it could have changed.
[Edit] For the purpose of highlighting the legality test now assumes a royaltyCount of 1 in the current position when in reality royaltyCount <= 0. In terms of scoring this fakes a single royal for the side that has none.
Technically you are right about that first point. I guess it was less of a visual bug and more of an inconvenience for tsume diagrams that would cause confusion for the solver, especially for large libraries of tsume problems like what I have in my Applet. Thanks for fixing it anyway, though.
Managed to make a tsumeshogi (mate in 17) involving a Kirin promotion deferral due to the bridge-capture rule.
lishogi.org/analysis/chushogi/1k+s3g5/v1n9/3iXo6/12/1O10/1+L+S+g8/12/2+t9/2x9/12/12/12_b_-_1
I have made a new version of the Chu Shogi Applet using a custom-built script. The link to the Applet now points to the new page. The old Applet is still available at a new page, whose membergraphics directory includes the old Applet by itself.
20 comments displayed
Permalink to the exact comments currently displayed.
The way I had in mind for indicating illegality of pseudo-legal moves in the NewClick highlighting routine was to make each move, and then generate all replies, and determine their scores. A king-capture score (15000) amongst these replies would mean the original move was illegal. This would then cause the grey cross to be used to highlight it.