Did anyone write a xiangqi chess engine?

Discussion of chess software programming and technical issues.

Moderator: Ras

User avatar
maksimKorzh
Posts: 775
Joined: Sat Sep 08, 2018 5:37 pm
Location: Ukraine
Full name: Maksim Korzh

Re: Did anyone write a xiangqi chess engine?

Post by maksimKorzh »

hgm wrote: Fri Jan 29, 2021 10:41 pm Supporting the Cyclone dialect if you already do orthodox UCI might indeed not be that difficult. All you have to do is understand r as w in the FEN parser, ignore 'position', and let 'fen' and 'startpos' do what "position fen" and "position startpos" used to do before. Then you would understand both dialects automatically. UCCI is a much tougher cookie; almost everything is different there. (It has for instance no 'name' and 'value' keywords, uses 'time' and 'oppotime' instead of 'wtime' and 'btime', with subtly different meaning for their values, etc.)

And of course you should not clear the hash table on receiving a FEN; this was bad practice anyway, even for orthodox UCI. There isn't even a real need to do it on 'ucinewgame'; as long as you are not playing another variant, the hash table left over from a previous game should also be valid for this one. Likely there isn't anything in there that you can use, but it should never hurt.
I've fixed TT reset and implemented cylone dialect, now IT WORKS! Hooray!
Here're 2 games, Wukong plays white in both cases, draws first, wins second:
[Event "Computer Chess Game"]
[Site "maksim-Inspiron-3582"]
[Date "2021.01.29"]
[Round "-"]
[White "WukongJS 1.0 (UCI2WB)"]
[Black "MaxQi 4.8F"]
[Result "1/2-1/2"]
[TimeControl "120+1"]
[Variant "xiangqi"]
[Annotator "1. +0,10 1... -0,08"]

1. Che2 {+0,10/7} Chg7 {-0,08/8 4} 2. Cxe6 {+0,22/8 4} Hc7 {-0,01/8 1,9} 3.
Ce4 {+0,24/8 4} Cb5 {-1,06/9 11} 4. Ce2 {+0,31/7 4} Ci5 {-1,09/7 1,6} 5.
Hi2 {+0,33/8 4} Rb9 {-1,09/7 2,4} 6. Rh0 {+0,33/7 3} Rb2 {-1,20/5 2,4} 7.
Rh5 {+0,65/6 3} g5 {-4,89/6 2,1} 8. Ci4+ {+2,57/7 3} Ege7 {-4,57/8 2,4} 9.
Rxi5 {+2,35/10 3} ixi5 {-4,80/8 1,9} 10. Cxi9 {+2,25/11 3} Rb4
{-4,75/8 1,8} 11. Hc2 {+2,68/8 3} g4 {-4,32/8 2,5} 12. Cg2 {+2,68/8 3} Cxg3
{-4,23/10 4} 13. Hxg3 {+2,74/11 3} gxg3 {-4,02/9 1,6} 14. Ci2 {+2,76/9 3}
Rb5 {-4,04/8 2,0} 15. c4 {+2,82/9 3} gf3 {-4,01/8 2,0} 16. Ra1 {+3,04/9 3}
Rh5 {-5,71/9 1,9} 17. Rf1 {+3,50/10 3} Rh3 {-5,71/8 1,9} 18. Hd4
{+3,48/9 3} Ae8 {-5,63/9 2,2} 19. Rxf3 {+3,72/9 3} Rh4 {-6,49/9 2,5} 20.
Hf5 {+3,70/9 2,9} Rh5 {-6,66/8 1,5} 21. Hd6 {+3,76/8 2,9} Rd5 {-6,71/8 1,6}
22. Rf6 {+4,34/9 2,9} Kd9 {-7,15/8 1,6} 23. Rh6 {+4,58/10 2,9} Kd8
{-7,07/7 1,3} 24. Ade1 {+4,58/7 2,9} Hf8 {-6,98/7 1,5} 25. Cxc9
{+4,95/9 2,8} Hce6 {-7,51/9 2,0} 26. Rf6 {+5,72/9 2,8} Rxd6 {-8,10/10 1,4}
27. Cd2+ {+5,93/9 2,8} Rxd2 {-12,09/13 3} 28. Axd2 {+7,51/11 2,7} c5
{-11,99/13 2,6} 29. Rxf8 {+7,83/11 2,7} cxc4 {-12,77/13 2,9} 30. Ce9
{+8,20/9 2,6} cd4 {-11,31/9 2,7} 31. Cxe7 {+8,12/11 2,6} Kd7
{-11,44/10 1,6} 32. Rf6 {+8,48/11 2,5} Hc5 {-12,16/10 1,5} 33. Rc6
{+8,50/10 2,5} Hb3 {-11,59/11 1,8} 34. Rc7+ {+8,63/10 2,5} Kd8
{-12,11/10 1,6} 35. Rc3 {+9,05/12 2,5} Ha5 {-13,39/9 2,0} 36. Rc8+
{+9,13/11 2,4} Kd7 {-11,58/10 2,1} 37. Rc7+ {+9,49/12 2,4} Kd8
{-11,75/10 3} 38. Ea2 {+9,75/12 2,3} d3 {-13,97/10 2,6} 39. a4
{+9,87/11 2,3} dxd2 {-14,00/9 2,6} 40. Rc5 {+10,23/12 2,2} Kd7
{-14,68/9 2,8} 41. Ci7 {+10,33/12 2,2} Ke7 {-14,93/9 1,2} 42. Rc7+
{+11,01/12 2,2} Ad7 {-15,82/10 1,4} 43. Cxd7 {+11,23/12 2,1} Ke8
{-15,88/9 1,1} 44. Ae1 {+11,67/12 2,1} Kd8 {-16,69/9 1,9} 45. Cd6
{+11,71/11 2,1} d1 {-17,73/9 1,1} 46. Rc8+ {+11,79/12 2,1} Kd7
{-18,41/11 2,5} 47. Rc7+ {+12,07/13 2,1} Kd8 {-5,01/28 0,1} 48. Rc8+
{+12,07/13 2,1} Kd7 {-5,01/19 1,1} 49. Rc7+ {+12,05/13 2,1} Kd8
{-5,01/28 0,1}
{Draw by repetition} 1/2-1/2

[Event "Computer Chess Game"]
[Site "maksim-Inspiron-3582"]
[Date "2021.01.29"]
[Round "-"]
[White "WukongJS 1.0 (UCI2WB)"]
[Black "MaxQi 4.8F"]
[Result "1-0"]
[TimeControl "120+1"]
[Variant "xiangqi"]
[Annotator "1. +0,10 1... +0,04"]

1. Che2 {+0,10/7} Cbg7 {+0,04/7 1,7} 2. Cxe6 {+0,12/8 4} Cxg3 {-0,29/8 6}
3. Ce2 {+0,34/8 4} Chh3 {-0,75/7 2,4} 4. Ce4 {+2,99/7 4} Cxe3+ {-4,13/8 3}
5. Afe1 {+2,97/8 4} Hi7 {-4,14/7 2,2} 6. Ca4+ {+5,00/9 4} Ege7
{-7,27/9 1,8} 7. Cxa9 {+5,78/11 4} Cxc3 {-7,66/10 2,4} 8. Hg2 {+5,78/10 4}
Ce4 {-7,39/9 1,9} 9. Ha2 {+5,84/9 4} Cc5 {-7,62/10 5} 10. Rb0 {+6,08/10 3}
Hc7 {-8,02/10 1,8} 11. Rb6 {+6,10/9 3} Ri8 {-8,78/9 2,6} 12. Rxc6
{+6,34/10 3} He8 {-9,66/10 4} 13. Rd6 {+7,38/9 3} Hc7 {-9,61/9 3} 14. Rd7
{+7,46/8 3} Ci5 {-12,57/10 5} 15. Rh0 {+8,61/9 3} Cie5 {-12,78/9 1,9} 16.
Rxc7 {+8,71/10 3} Ra8 {-12,86/8 2,0} 17. Rh7 {+8,75/9 3} Rxa9
{-13,43/8 1,5} 18. Rxi7 {+8,87/10 3} g5 {-13,66/8 1,4} 19. Rxi6
{+8,99/9 2,9} Cxe2+ {-13,96/10 4} 20. Ecxe2 {+9,03/9 2,8} Ce5
{-13,70/9 1,4} 21. Re6 {+9,07/9 2,8} Cb5 {-14,39/10 1,9} 22. Rc5
{+9,07/8 2,8} Cb8 {-14,50/10 2,1} 23. Rxg5 {+9,29/8 2,8} a5 {-14,60/10 7}
24. Rd5 {+9,31/7 2,6} a4 {-14,58/9 1,7} 25. Rd8 {+10,09/8 2,5} Cb2
{-14,16/10 1,3} 26. Rxe7+ {+10,03/9 2,5} Afe8 {-14,17/9 1,2} 27. Hf4
{+10,08/9 2,5} axa3 {-14,08/10 2,0} 28. Hb0 {+10,03/8 2,5} ab3 {-14,29/9 3}
29. Re3 {+10,14/8 2,4} Ra3 {-15,84/11 1,9} 30. Rdd3 {+10,25/8 2,4} Ra0
{-16,08/12 3} 31. Hc2 {+10,43/9 2,3} Ra4 {-15,92/10 2,2} 32. Rxb3
{+10,47/9 2,3} Ca2 {-16,03/10 1,2} 33. He6 {+10,51/8 2,2} Ra5
{-16,11/9 1,6} 34. Ra3 {+10,55/7 2,2} Rxa3 {-17,39/13 1,5} 35. Rxa3
{+11,57/10 2,2} Cb2 {-17,38/12 1,1} 36. Rc3 {+11,63/10 2,2} Ee7
{-17,33/10 2,0} 37. Rc7 {+11,69/10 2,2} Cb5 {-17,66/11 1,3} 38. Rxe7
{+11,77/11 2,2} Ce5 {-18,40/12 1,8} 39. Hg7 {+11,79/10 2,1} Ca5
{-18,52/13 1,2} 40. Hd4 {+11,81/10 2,2} Ca0+ {-18,47/12 1,9} 41. Ec0
{+15,80/11 2,1} Ca3 {-21,59/12 1,1} 42. Hdf5 {+1000,05/10 0,8} Cf3
{-79,95/15 1,4} 43. Hd6 {+1000,02/4 0,1} Cf8 {-79,96/19 1,3} 44. Hf7#
{+1000,01/2 0,1}
{Xboard adjudication: Stalemate} 1-0

Could you please have a look at the games?
Both engines hitting the same depth - around 7-9 plies in the opening and 10-12 in the endgame.
It seems like Wukong is winning material all of the time.
I guess microMax is much stronger that MaxQi (if we could compare them), well at least microMax crushes my classical WukongJS.

Question: why 3 fold rep is treated to be a draw? Isn't it a loss?
Assumption: I guess Wukong is better because of the eval I've grabbed form other engine (material/PST only traditionally)

Could you please test Wukong vs MaxQi on your side on windows?
If it works, could you please provide your exact setup (uci2wb version, download link for it, command to run winboard)
I just want to provide that in the readme.
Despite the fact it's supposed to be used within the GUI, still I want to give instructions for those crazy testers who will want to try it.
https://github.com/maksimKorzh/wukong-x ... src/engine
to run in bare console: "node uci-cyclone.js"

I used this uci2wb from here:
https://github.com/ianfab/uci2wb

hgm, are you proud of me now))) ?
User avatar
hgm
Posts: 28398
Joined: Fri Mar 10, 2006 10:06 am
Location: Amsterdam
Full name: H G Muller

Re: Did anyone write a xiangqi chess engine?

Post by hgm »

Yes, good job!

MaxQi is indeed probably not very strong. I never did any tuning on its evaluation; I was happy after I implemented the rules. At the time I made it, there existed only one other XBoard engine that could play Xiangqi (HoiXiangqi, a derivative of HoiChess), and MaxQi could already beat that. Playing UCCI Xiangqi engines on XBoard/WinBoard was not possible at that time. And I was already working on a 'serious' Xiangqi engine (HaQiKi D).

I discovered that the PST are very important in Xiangqi. In the early statges of its development I tested HaQiKi D against XQ Wizard Light, which was a UCCI engine (a stripped-down version of Elephant Eye, that came with the XQ Wizard GUI), of which I had made an XBoard version. Although HaQiKi D was searching at least 4 ply deeper, it was still clobbered by XQWL. Just because of wrong PST, which did not advance the Horses and (especially) Pawns aggressively enough towards the enemy Palace. Only after I corrected HaQiKi D's PST it could beat XQWL without much effort.

BTW, an other important pitfall in Xiangqi is pinned Cannons. When a Cannon is between two Rooks of different color, it is pinned on the friendly Rook, unless the latter is protected. But especially along the b- and h-file it can be very difficult to protect the Rook; Elephants (and of course King and Advisors) cannot get to those files, and you cannot move the Rook out of the file without abandoning the Cannon. If a Horse is similarly pinned you can manoeuvre such that you finally move the Horse away from the file in a way that it protects the Rook, but with a Cannon that is not possible, and it can very well be that you are stuck with this pin for the rest of the game. (So that you effectively also are a Cannon behind, because the single opponent Rook prevents you to use your Cannon + Rook.) This is usually fatal.

You are right about the first game; this should be a win for black, as white is perpetually checking. The game result is not determined by XBoard, however. (Because then the result message would have said: "XBoard adjudication: ...".) It was MaxQi that claimed the draw here, as it doesn't know any better. (These result messages are a remnant of its micro-Max ancestry, and thus consider every repetition a draw; I never bothered to change them, as it cannot accurately rule the perpetuals anyway.) Either the XBoard adjudication was switched off, or its legality testing, (which would also preclude adjudication), and the verification of engine claims. With those things switched on it would already have declared the offending black move a loss even before relaying it to MaxQi, so that the latter would never have gotten the chance to make a (false) result claim.

I won't have much time for any testing today, as it is my wife's birthday.
User avatar
maksimKorzh
Posts: 775
Joined: Sat Sep 08, 2018 5:37 pm
Location: Ukraine
Full name: Maksim Korzh

Re: Did anyone write a xiangqi chess engine?

Post by maksimKorzh »

Thank you so much for your support, without your help I wouldn't been there where I am now.
MaxQi is indeed probably not very strong. I never did any tuning on its evaluation; I was happy after I implemented the rules. At the time I made it, there existed only one other XBoard engine that could play Xiangqi (HoiXiangqi, a derivative of HoiChess), and MaxQi could already beat that. Playing UCCI Xiangqi engines on XBoard/WinBoard was not possible at that time. And I was already working on a 'serious' Xiangqi engine (HaQiKi D).
Anyway I'm very greatful for providing TSCP-like opponent to play with.
I discovered that the PST are very important in Xiangqi. In the early statges of its development I tested HaQiKi D against XQ Wizard Light, which was a UCCI engine (a stripped-down version of Elephant Eye, that came with the XQ Wizard GUI), of which I had made an XBoard version. Although HaQiKi D was searching at least 4 ply deeper, it was still clobbered by XQWL. Just because of wrong PST, which did not advance the Horses and (especially) Pawns aggressively enough towards the enemy Palace. Only after I corrected HaQiKi D's PST it could beat XQWL without much effort.
I used PST from "Li, Cuanqi 2008, "Using AdaBoost to Implement Chinese Chess Evaluation Functions", UCLA thesis"
and piece weights from

Code: Select all

// material weights
    const MATERIAL_WEIGHTS = [
      //  P     A     B     N     C     R      K   
      0, 30,  120,  120,  270,  285,  600,  6000,
      
      //  p     a     b     n     c     r      k
        -30, -120, -120, -270, -285, -600, -6000
    ];

    // piece square tables
    const PST = [
      // pawns
      [
        0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
        0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
        0,   0,   3,   6,   9,  12,   9,   6,   3,   0,   0,
        0,  18,  36,  56,  80, 120,  80,  56,  36,  18,   0,
        0,  14,  26,  42,  60,  80,  60,  42,  26,  14,   0, 
        0,  10,  20,  30,  34,  40,  34,  30,  20,  10,   0, 
        0,   6,  12,  18,  18,  20,  18,  18,  12,   6,   0, 
        0,   2,   0,   8,   0,   8,   0,   8,   0,   2,   0, 
        0,   0,   0,  -2,   0,   4,   0,  -2,   0,   0,   0, 
        0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 
        0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 
        0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
        0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
        0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0
      ],
      
      
      [],  // skip advisors
      [],  // skip bishops
      
      // knights
      [
        0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
        0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
        0,   4,   8,  16,  12,   4,  12,  16,   8,   4,   0,
        0,   4,  10,  28,  16,   8,  16,  28,  10,   4,   0, 
        0,  12,  14,  16,  20,  18,  20,  16,  14,  12,   0, 
        0,   8,  24,  18,  24,  20,  24,  18,  24,   8,   0, 
        0,   6,  16,  14,  18,  16,  18,  14,  16,   6,   0, 
        0,   4,  12,  16,  14,  12,  14,  16,  12,   4,   0, 
        0,   2,   6,   8,   6,  10,   6,   8,   6,   2,   0, 
        0,   4,   2,   8,   8,   4,   8,   8,   2,   4,   0, 
        0,   0,   2,   4,   4,  -2,   4,   4,   2,   0,   0, 
        0,   0,  -4,   0,   0,   0,   0,   0,  -4,   0,   0,
        0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
        0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0
      ],
      
      // cannon
      [
        0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
        0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
        0,   6,   4,   0, -10, -12, -10,   0,   4,   6,   0,
        0,   2,   2,   0,  -4, -14,  -4,   0,   2,   2,   0, 
        0,   2,   2,   0, -10,  -8, -10,   0,   2,   2,   0, 
        0,   0,   0,  -2,   4,  10,   4,  -2,   0,   0,   0, 
        0,   0,   0,   0,   2,   8,   2,   0,   0,   0,   0, 
        0,  -2,   0,   4,   2,   6,   2,   4,   0,  -2,   0, 
        0,   0,   0,   0,   2,   4,   2,   0,   0,   0,   0, 
        0,   4,   0,   8,   6,  10,   6,   8,   0,   4,   0, 
        0,   0,   2,   4,   6,   6,   6,   4,   2,   0,   0, 
        0,   0,   0,   2,   6,   6,   6,   2,   0,   0,   0,
        0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
        0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0
      ],
      
      // rooks
      [
        0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
        0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
        0,  14,  14,  12,  18,  16,  18,  12,  14,  14,   0,
        0,  16,  20,  18,  24,  26,  24,  18,  20,  16,   0, 
        0,  12,  12,  12,  18,  18,  18,  12,  12,  12,   0, 
        0,  12,  18,  16,  22,  22,  22,  16,  18,  12,   0, 
        0,  12,  14,  12,  18,  18,  18,  12,  14,  12,   0, 
        0,  12,  16,  14,  20,  20,  20,  14,  16,  12,   0, 
        0,   6,  10,   8,  14,  14,  14,   8,  10,   6,   0, 
        0,   4,   8,   6,  14,  12,  14,   6,   8,   4,   0, 
        0,   8,   4,   8,  16,   8,  16,   8,   4,   8,   0, 
        0,  -2,  10,   6,  14,  12,  14,   6,  10,  -2,   0,
        0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
        0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0
      ],
      
      []  // skip kings
    ];
Note the difference in piece weights in comparison with CPW values,
btw these values is somewhat how I "feel" piece weights when play as a human
(I've just started, but still)
BTW, an other important pitfall in Xiangqi is pinned Cannons. When a Cannon is between two Rooks of different color, it is pinned on the friendly Rook, unless the latter is protected. But especially along the b- and h-file it can be very difficult to protect the Rook; Elephants (and of course King and Advisors) cannot get to those files, and you cannot move the Rook out of the file without abandoning the Cannon. If a Horse is similarly pinned you can manoeuvre such that you finally move the Horse away from the file in a way that it protects the Rook, but with a Cannon that is not possible, and it can very well be that you are stuck with this pin for the rest of the game. (So that you effectively also are a Cannon behind, because the single opponent Rook prevents you to use your Cannon + Rook.) This is usually fatal.
I guess this is one of the core reasons behind opening ideas in xiangqi - people are trying to put a knight in between of two canons in order
to make latter supporting each other and wen it comes to mating attack - canons are more often coordinated with knights while rooks are
used together to give a linear mate like in classical chess (I don't eve know now which chess do I consider to be classical))) )
You are right about the first game; this should be a win for black, as white is perpetually checking. The game result is not determined by XBoard, however. (Because then the result message would have said: "XBoard adjudication: ...".) It was MaxQi that claimed the draw here, as it doesn't know any better. (These result messages are a remnant of its micro-Max ancestry, and thus consider every repetition a draw; I never bothered to change them, as it cannot accurately rule the perpetuals anyway.) Either the XBoard adjudication was switched off, or its legality testing, (which would also preclude adjudication), and the verification of engine claims. With those things switched on it would already have declared the offending black move a loss even before relaying it to MaxQi, so that the latter would never have gotten the chance to make a (false) result claim.
I now realize why the idea of using only cannon weight as a margin - in first game Wukong was so much material up that going for 3 fold rep at the cost of a single cannon was just fine. I still think that evaluating reps as mate is better because that's literally what it leads to and even if engine would start sacrificing material to avoid that - I guess in winning positions it's still ok while in lost ones it doesn't matter anymore. I'll play around with that a bit later.
I won't have much time for any testing today, as it is my wife's birthday.
Congrats from Code Monkey King!
User avatar
hgm
Posts: 28398
Joined: Fri Mar 10, 2006 10:06 am
Location: Amsterdam
Full name: H G Muller

Re: Did anyone write a xiangqi chess engine?

Post by hgm »

maksimKorzh wrote: Sat Jan 30, 2021 5:16 pmI still think that evaluating reps as mate is better because that's literally what it leads to ...
The point is that the repetition might not be lost at all. Not all repetitions are lost. Usually you cannot force repetitions without being at fault (this is sort of what the rules try to formalize), but sometimes you can. In particular the situations 'one chases two' or alternating checks with mate threats frequently lead to draws. E.g.

[d]r2fk4/r3f4/4e4/2p5p/5R3/4O4/9/4E4/4F4/2E1KF3 w

1. Rh5 {threatens Rh9#} Kf9 2. Rf5+ Ke9 3. Rh5 Kf9 ... forces a repetition draw. It is not perpetual checking, as Rh5 does not deliver check. Mate threats do not count as chases, under 'Asia rule'.

Or a one-chases-two position:

[d]o2fk4/1R2f4/e8/9/2e5h/9/2H4h1/E8/o3F4/2EFK4 w

1. Rb9 Ca8 2. Rb1 Ca0 3. Rb8 Ca9 4. Rb0 Ca1 5. Rb9 Ca8 ... would lead to a draw, unless black is prepared to sacrifice a Cannon through CxE. Not all moves in the repetition loop attack the same Cannon, so it is not a perpetual chase.
User avatar
maksimKorzh
Posts: 775
Joined: Sat Sep 08, 2018 5:37 pm
Location: Ukraine
Full name: Maksim Korzh

Re: Did anyone write a xiangqi chess engine?

Post by maksimKorzh »

hgm wrote: Sat Jan 30, 2021 11:27 pm
maksimKorzh wrote: Sat Jan 30, 2021 5:16 pmI still think that evaluating reps as mate is better because that's literally what it leads to ...
The point is that the repetition might not be lost at all. Not all repetitions are lost. Usually you cannot force repetitions without being at fault (this is sort of what the rules try to formalize), but sometimes you can. In particular the situations 'one chases two' or alternating checks with mate threats frequently lead to draws. E.g.

[d]r2fk4/r3f4/4e4/2p5p/5R3/4O4/9/4E4/4F4/2E1KF3 w

1. Rh5 {threatens Rh9#} Kf9 2. Rf5+ Ke9 3. Rh5 Kf9 ... forces a repetition draw. It is not perpetual checking, as Rh5 does not deliver check. Mate threats do not count as chases, under 'Asia rule'.

Or a one-chases-two position:

[d]o2fk4/1R2f4/e8/9/2e5h/9/2H4h1/E8/o3F4/2EFK4 w

1. Rb9 Ca8 2. Rb1 Ca0 3. Rb8 Ca9 4. Rb0 Ca1 5. Rb9 Ca8 ... would lead to a draw, unless black is prepared to sacrifice a Cannon through CxE. Not all moves in the repetition loop attack the same Cannon, so it is not a perpetual chase.
I've just realized that forgot to write hash key into repetition table in make move))))
So Wukong lost to MaqQi not because of wrong reps scoring but because it simple didn't see reps)))

P.S. I'm almost done with a nice cute browser GUI, release is coming soon!
Will you play it as a human)?
User avatar
hgm
Posts: 28398
Joined: Fri Mar 10, 2006 10:06 am
Location: Amsterdam
Full name: H G Muller

Re: Did anyone write a xiangqi chess engine?

Post by hgm »

I have never played this game as a human.
User avatar
maksimKorzh
Posts: 775
Joined: Sat Sep 08, 2018 5:37 pm
Location: Ukraine
Full name: Maksim Korzh

Re: Did anyone write a xiangqi chess engine?

Post by maksimKorzh »

hgm wrote: Sun Jan 31, 2021 12:03 pm I have never played this game as a human.
Now you can try)
Starting from playing versus random moves level)
https://maksimkorzh.github.io/wukong-xi ... angqi.html