Did anyone write a xiangqi chess engine?
Moderators: hgm, Rebel, chrisw
-
- Posts: 12541
- Joined: Wed Mar 08, 2006 8:57 pm
- Location: Redmond, WA USA
Re: Did anyone write a xiangqi chess engine?
Shogi is next. You get to drop pieces out of your hand onto the board during the game, not just for promotion.
Taking ideas is not a vice, it is a virtue. We have another word for this. It is called learning.
But sharing ideas is an even greater virtue. We have another word for this. It is called teaching.
But sharing ideas is an even greater virtue. We have another word for this. It is called teaching.
-
- Posts: 27808
- Joined: Fri Mar 10, 2006 10:06 am
- Location: Amsterdam
- Full name: H G Muller
Re: Did anyone write a xiangqi chess engine?
Yes, it is a rather exciting game. At high level it suffers from the same drawishness problem as FIDE Chess, though. As Dann says, Shogi is also very exciting, and doesn't have a drawishness problem.maksimKorzh wrote: ↑Sat Jan 23, 2021 1:05 am Oh my god! Oh my god!!!
I've just tried to play this game!!!
Ahhhh!!!
What a fantastic experience!
What an exciting stuff!
Now I will definitely go for coding an engine for it, I swear!
Also I've just realized that I want to master this game as a human player.
What gave you that idea? Chess variants are very much on topic here. In fact they are the topic: FIDE Chess is just one of the variants, with rules quite different from the original game as it existed 1300 years ago. And it is not even the most popular variant in the world (which is Xiangqi).I know chess variants are off topic here but I hope it would be fine answer some questions within this thread)
Guys I don't know why but I feel so happy!
Ask anything you like. I never played it myself, but it is amazing how much you learn from watching engines play. And I did that a lot.
-
- Posts: 771
- Joined: Sat Sep 08, 2018 5:37 pm
- Location: Ukraine
- Full name: Maksim Korzh
Re: Did anyone write a xiangqi chess engine?
Thanks for your support mr.Muller.hgm wrote: ↑Sat Jan 23, 2021 10:19 amYes, it is a rather exciting game. At high level it suffers from the same drawishness problem as FIDE Chess, though. As Dann says, Shogi is also very exciting, and doesn't have a drawishness problem.maksimKorzh wrote: ↑Sat Jan 23, 2021 1:05 am Oh my god! Oh my god!!!
I've just tried to play this game!!!
Ahhhh!!!
What a fantastic experience!
What an exciting stuff!
Now I will definitely go for coding an engine for it, I swear!
Also I've just realized that I want to master this game as a human player.
What gave you that idea? Chess variants are very much on topic here. In fact they are the topic: FIDE Chess is just one of the variants, with rules quite different from the original game as it existed 1300 years ago. And it is not even the most popular variant in the world (which is Xiangqi).I know chess variants are off topic here but I hope it would be fine answer some questions within this thread)
Guys I don't know why but I feel so happy!
Ask anything you like. I never played it myself, but it is amazing how much you learn from watching engines play. And I did that a lot.
Today I'm starting my very first xiangqi engine so I'would probably start torturing you soon with uprising questions)))
P.S. Btw today is also a release of WukongJS 1.5
https://github.com/maksimKorzh/wukongJS
Didactic chess engines:
https://www.chessprogramming.org/Maksim_Korzh
Chess programming YouTube channel:
https://www.youtube.com/channel/UCB9-pr ... KKqDgXhsMQ
https://www.chessprogramming.org/Maksim_Korzh
Chess programming YouTube channel:
https://www.youtube.com/channel/UCB9-pr ... KKqDgXhsMQ
-
- Posts: 4833
- Joined: Sun Aug 10, 2008 3:15 pm
- Location: Philippines
Re: Did anyone write a xiangqi chess engine?
I got here a perft data based from Makulit xiangqi engine.maksimKorzh wrote: ↑Fri Jan 22, 2021 11:13 pm Any perft tests available for xiangqi?
Maybe using existing engines to calibrate movegen is on the cards?
Any positions like Kiwipete to catch the most common bugs of movegen?
Is FEN-like position representation available?
PGN?
Move format?
You may post here if your figures does not agree with it.
-
- Posts: 771
- Joined: Sat Sep 08, 2018 5:37 pm
- Location: Ukraine
- Full name: Maksim Korzh
Re: Did anyone write a xiangqi chess engine?
Oh, thank you so much, Ferdinand!
That's exactly what I was looking for!
Just brilliant!
That's exactly what I was looking for!
Just brilliant!
Didactic chess engines:
https://www.chessprogramming.org/Maksim_Korzh
Chess programming YouTube channel:
https://www.youtube.com/channel/UCB9-pr ... KKqDgXhsMQ
https://www.chessprogramming.org/Maksim_Korzh
Chess programming YouTube channel:
https://www.youtube.com/channel/UCB9-pr ... KKqDgXhsMQ
-
- Posts: 771
- Joined: Sat Sep 08, 2018 5:37 pm
- Location: Ukraine
- Full name: Maksim Korzh
Re: Did anyone write a xiangqi chess engine?
Question on winboard
So I'm running it via wine on linux, seems to be working nicely so far.
So it supports UCCI protocol right?
If I want to run JS engine I need to specify to node.exe and path to JS file as command line argument, right?
Question on UCCI move format (seems like UCI):
so let's say we have a move c3c4, let's just assume it exists and it's legal but
what's the layout for file and ranks?
Xiangqi players using very specific notation for game which is different from UCI,
so is there a standard to specify files/ranks layout?
FIles horizontal?
Ranks vertical?
So say I'm playing red (white) and want to make move "left canon supports central pawn" -
how it would be encoded in UCI format?
Winboard seems to use somewhat that looks like SAN notation.
Is there a way to see debug like in arena gui where I can track of commands, e.g.
position startpos moves .... ?
EDIT:
Ok, it seems the layout is clear
Files (see board from red perspective from left to right): a b c d e f g h f
Ranks (starting from red perspective from bottom to top): 0 1 2 3 4 5 6 7 8 9
What confuses me is that ranks are starting from 0, not from 1, is that a UCI standard? same for UCCI?
So I'm running it via wine on linux, seems to be working nicely so far.
So it supports UCCI protocol right?
If I want to run JS engine I need to specify to node.exe and path to JS file as command line argument, right?
Question on UCCI move format (seems like UCI):
so let's say we have a move c3c4, let's just assume it exists and it's legal but
what's the layout for file and ranks?
Xiangqi players using very specific notation for game which is different from UCI,
so is there a standard to specify files/ranks layout?
FIles horizontal?
Ranks vertical?
So say I'm playing red (white) and want to make move "left canon supports central pawn" -
how it would be encoded in UCI format?
Winboard seems to use somewhat that looks like SAN notation.
Is there a way to see debug like in arena gui where I can track of commands, e.g.
position startpos moves .... ?
EDIT:
Ok, it seems the layout is clear
Files (see board from red perspective from left to right): a b c d e f g h f
Ranks (starting from red perspective from bottom to top): 0 1 2 3 4 5 6 7 8 9
What confuses me is that ranks are starting from 0, not from 1, is that a UCI standard? same for UCCI?
Didactic chess engines:
https://www.chessprogramming.org/Maksim_Korzh
Chess programming YouTube channel:
https://www.youtube.com/channel/UCB9-pr ... KKqDgXhsMQ
https://www.chessprogramming.org/Maksim_Korzh
Chess programming YouTube channel:
https://www.youtube.com/channel/UCB9-pr ... KKqDgXhsMQ
-
- Posts: 771
- Joined: Sat Sep 08, 2018 5:37 pm
- Location: Ukraine
- Full name: Maksim Korzh
Re: Did anyone write a xiangqi chess engine?
Ok all above seems to be now clear.
The next confusing thing is mailbox size.
I had a look at some engines - many use 256 array (16x16)
but it seems like 14x11 should be fairly enough (analog of 10x12 for common chess)
With this size pieces already should not jump over ranks.
So why 16x16 used?
To HGM: in maxQi I see b[513] // 16 x 8 + dummy + PST
this is a bit confusing...
So what would be the array size without dummy square and PST? (how many files x ranks)?
The next confusing thing is mailbox size.
I had a look at some engines - many use 256 array (16x16)
but it seems like 14x11 should be fairly enough (analog of 10x12 for common chess)
With this size pieces already should not jump over ranks.
So why 16x16 used?
To HGM: in maxQi I see b[513] // 16 x 8 + dummy + PST
this is a bit confusing...
So what would be the array size without dummy square and PST? (how many files x ranks)?
Didactic chess engines:
https://www.chessprogramming.org/Maksim_Korzh
Chess programming YouTube channel:
https://www.youtube.com/channel/UCB9-pr ... KKqDgXhsMQ
https://www.chessprogramming.org/Maksim_Korzh
Chess programming YouTube channel:
https://www.youtube.com/channel/UCB9-pr ... KKqDgXhsMQ
-
- Posts: 1437
- Joined: Wed Apr 21, 2010 4:58 am
- Location: Australia
- Full name: Nguyen Hong Pham
Re: Did anyone write a xiangqi chess engine?
Theory, you can use the "standard" margins as chess, 2 cells. It means the board 9x10 should become 11x14 (left and right sides can share their columns thus they need 11 instead of 13) as the minimum. Thus you got that size already. If you want to save some commands of dividing, use 16, thus we may have that size 16x14 or 16x16maksimKorzh wrote: ↑Sun Jan 24, 2021 4:16 am Ok all above seems to be now clear.
The next confusing thing is mailbox size.
I had a look at some engines - many use 256 array (16x16)
but it seems like 14x11 should be fairly enough (analog of 10x12 for common chess)
With this size pieces already should not jump over ranks.
So why 16x16 used?
To HGM: in maxQi I see b[513] // 16 x 8 + dummy + PST
this is a bit confusing...
So what would be the array size without dummy square and PST? (how many files x ranks)?
I have used the mailbox with margins for a while and then realized it could help to save few commands IF only, does important nowadays, especially Xiangqi needs more specific code depending on piece’s type. The large board is not free but including some other disadvantages. After that, whenever I need a mailbox for Xiangqi, I simply use 9x10 = 90 cells and quite happy with its simpleness.
Here if you want to see the real code:
Code: Select all
Piece pieces[90];
The move generator is quite straightforward and simple too:
Code: Select all
void EgtbBoard::gen(MoveList& moves, Side side, bool captureOnly) const {
moves.reset();
for (int l = 0; l < 16; l++) {
auto pos = pieceList[static_cast<int>(side)][l];
if (pos < 0) {
continue;
}
auto piece = pieces[pos];
switch (piece.type) {
case PieceType::king:
{
int col = pos % 9;
if (col != 3) { // go left
gen_addMove(moves, pos, pos - 1, captureOnly);
}
if (col != 5) { // right
gen_addMove(moves, pos, pos + 1, captureOnly);
}
if (pos > 72 || (pos > 8 && pos < 27)) { // up
gen_addMove(moves, pos, pos - 9, captureOnly);
}
if (pos < 18 || (pos > 63 && pos < 81)) { // down
gen_addMove(moves, pos, pos + 9, captureOnly);
}
break;
}
case PieceType::advisor:
{
int y = pos - 10; /* go left up */
if (y == 3 || y == 13 || y == 66 || y == 76) {
gen_addMove(moves, pos, y, captureOnly);
}
y = pos - 8; /* go right up */
if (y == 5 || y == 13 || y == 68 || y == 76) {
gen_addMove(moves, pos, y, captureOnly);
}
y = pos + 8; /* go left down */
if (y == 13 || y == 21 || y == 84 || y == 76) {
gen_addMove(moves, pos, y, captureOnly);
}
y = pos + 10; /* go right down */
if (y == 13 || y == 23 || y == 76 || y == 86) {
gen_addMove(moves, pos, y, captureOnly);
}
break;
}
case PieceType::elephant:
{
int y = pos - 20; /* go left up */
if ((y == 2 || y == 6 || y == 18 || y == 22 || y == 47 || y == 51 || y == 63 || y == 67) && isEmpty(pos - 10)) {
gen_addMove(moves, pos, y, captureOnly);
}
y = pos - 16; /* go right up */
if ((y == 2 || y == 6 || y == 22 || y == 26 || y == 47 || y == 51 || y == 67 || y == 71) && isEmpty(pos - 8)) {
gen_addMove(moves, pos, y, captureOnly);
}
y = pos + 16; /* go left down */
if ((y == 18 || y == 22 || y == 38 || y == 42 || y == 63 || y == 67 || y == 83 || y == 87) && isEmpty(pos + 8)) {
gen_addMove(moves, pos, y, captureOnly);
}
y = pos + 20; /* go right up */
if ((y == 22 || y == 26 || y == 38 || y == 42 || y == 67 || y == 71 || y == 83 || y == 87) && isEmpty(pos + 10)) {
gen_addMove(moves, pos, y, captureOnly);
}
break;
}
case PieceType::cannon: {
int col = pos % 9;
/*
* go left
*/
int f = 0;
for (int y=pos - 1; y >= pos - col; y--) {
if (isEmpty(y)) {
if (f == 0 && !captureOnly) {
gen_addMove(moves, pos, y, captureOnly);
}
continue;
}
f++;
if (f == 2) {
gen_addMove(moves, pos, y, captureOnly);
break;
}
}
/*
* go right
*/
f = 0;
for (int y=pos + 1; y < pos - col + 9; y++) {
if (isEmpty(y)) {
if (f == 0 && !captureOnly) {
gen_addMove(moves, pos, y, captureOnly);
}
continue;
}
f++;
if (f == 2) {
gen_addMove(moves, pos, y, captureOnly);
break;
}
}
f = 0;
for (int y=pos - 9; y >= 0; y -= 9) { /* go up */
if (isEmpty(y)) {
if (f == 0 && !captureOnly) {
gen_addMove(moves, pos, y, captureOnly);
}
continue;
}
f += 1 ;
if (f == 2) {
gen_addMove(moves, pos, y, captureOnly);
break;
}
}
f = 0;
for (int y=pos + 9; y < 90; y += 9) { /* go down */
if (isEmpty(y)) {
if (f == 0 && !captureOnly) {
gen_addMove(moves, pos, y, captureOnly);
}
continue;
}
f += 1 ;
if (f == 2) {
gen_addMove(moves, pos, y, captureOnly);
break;
}
}
break;
}
case PieceType::rook:
{
int col = pos % 9;
for (int y=pos - 1; y >= pos - col; y--) { /* go left */
gen_addMove(moves, pos, y, captureOnly);
if (!isEmpty(y)) {
break;
}
}
for (int y=pos + 1; y < pos - col + 9; y++) { /* go right */
gen_addMove(moves, pos, y, captureOnly);
if (!isEmpty(y)) {
break;
}
}
for (int y=pos - 9; y >= 0; y -= 9) { /* go up */
gen_addMove(moves, pos, y, captureOnly);
if (!isEmpty(y)) {
break;
}
}
for (int y=pos + 9; y < 90; y += 9) { /* go down */
gen_addMove(moves, pos, y, captureOnly);
if (!isEmpty(y)) {
break;
}
}
break;
}
case PieceType::horse:
{
int col = pos % 9;
int y = pos - 11;
int z = pos - 1;
if (y >= 0 && col > 1 && isEmpty(z)) {
gen_addMove(moves, pos, y, captureOnly);
}
y = pos - 19;
z = pos - 9;
if (y >= 0 && col > 0 && isEmpty(z)) {
gen_addMove(moves, pos, y, captureOnly);
}
y = pos - 17;
z = pos - 9;
if (y >= 0 && col < 8 && isEmpty(z)) {
gen_addMove(moves, pos, y, captureOnly);
}
y = pos - 7;
z = pos + 1;
if (y >= 0 && col < 7 && isEmpty(z)) {
gen_addMove(moves, pos, y, captureOnly);
}
y = pos + 7;
z = pos - 1;
if (y < 90 && col > 1 && isEmpty(z)) {
gen_addMove(moves, pos, y, captureOnly);
}
y = pos + 17;
z = pos + 9;
if (y < 90 && col > 0 && isEmpty(z)) {
gen_addMove(moves, pos, y, captureOnly);
}
y = pos + 19;
z = pos + 9;
if (y < 90 && col < 8 && isEmpty(z)) {
gen_addMove(moves, pos, y, captureOnly);
}
y = pos + 11;
z = pos + 1;
if (y < 90 && col < 7 && isEmpty(z)) {
gen_addMove(moves, pos, y, captureOnly);
}
break;
}
case PieceType::pawn:
{
if ((side == Side::black && pos > 44) || (side == Side::white && pos < 45)) {
int col = pos % 9;
/* go left */
if (col > 0) {
gen_addMove(moves, pos, pos - 1, captureOnly);
}
/* go right */
if (col < 8) {
gen_addMove(moves, pos, pos + 1, captureOnly);
}
}
if (side == Side::black) {
/* go down */
if (pos < 81) {
gen_addMove(moves, pos, pos + 9, captureOnly);
}
} else {
/* go up */
if (pos > 8) {
gen_addMove(moves, pos, pos - 9, captureOnly);
}
}
break;
}
default:
break;
}
}
}
https://banksiagui.com
The most features chess GUI, based on opensource Banksia - the chess tournament manager
The most features chess GUI, based on opensource Banksia - the chess tournament manager
-
- Posts: 771
- Joined: Sat Sep 08, 2018 5:37 pm
- Location: Ukraine
- Full name: Maksim Korzh
Re: Did anyone write a xiangqi chess engine?
Hold on a sec, so this code snippet relies on 9x10 array? I just can't figure out how/where do you check for offboard squares?phhnguyen wrote: ↑Sun Jan 24, 2021 6:37 amTheory, you can use the "standard" margins as chess, 2 cells. It means the board 9x10 should become 11x14 (left and right sides can share their columns thus they need 11 instead of 13) as the minimum. Thus you got that size already. If you want to save some commands of dividing, use 16, thus we may have that size 16x14 or 16x16maksimKorzh wrote: ↑Sun Jan 24, 2021 4:16 am Ok all above seems to be now clear.
The next confusing thing is mailbox size.
I had a look at some engines - many use 256 array (16x16)
but it seems like 14x11 should be fairly enough (analog of 10x12 for common chess)
With this size pieces already should not jump over ranks.
So why 16x16 used?
To HGM: in maxQi I see b[513] // 16 x 8 + dummy + PST
this is a bit confusing...
So what would be the array size without dummy square and PST? (how many files x ranks)?
I have used the mailbox with margins for a while and then realized it could help to save few commands IF only, does important nowadays, especially Xiangqi needs more specific code depending on piece’s type. The large board is not free but including some other disadvantages. After that, whenever I need a mailbox for Xiangqi, I simply use 9x10 = 90 cells and quite happy with its simpleness.
Here if you want to see the real code:
Source: https://github.com/nguyenpham/FelicityE ... gtbBoard.hCode: Select all
Piece pieces[90];
The move generator is quite straightforward and simple too:
Code: Select all
void EgtbBoard::gen(MoveList& moves, Side side, bool captureOnly) const { moves.reset(); for (int l = 0; l < 16; l++) { auto pos = pieceList[static_cast<int>(side)][l]; if (pos < 0) { continue; } auto piece = pieces[pos]; switch (piece.type) { case PieceType::king: { int col = pos % 9; if (col != 3) { // go left gen_addMove(moves, pos, pos - 1, captureOnly); } if (col != 5) { // right gen_addMove(moves, pos, pos + 1, captureOnly); } if (pos > 72 || (pos > 8 && pos < 27)) { // up gen_addMove(moves, pos, pos - 9, captureOnly); } if (pos < 18 || (pos > 63 && pos < 81)) { // down gen_addMove(moves, pos, pos + 9, captureOnly); } break; } case PieceType::advisor: { int y = pos - 10; /* go left up */ if (y == 3 || y == 13 || y == 66 || y == 76) { gen_addMove(moves, pos, y, captureOnly); } y = pos - 8; /* go right up */ if (y == 5 || y == 13 || y == 68 || y == 76) { gen_addMove(moves, pos, y, captureOnly); } y = pos + 8; /* go left down */ if (y == 13 || y == 21 || y == 84 || y == 76) { gen_addMove(moves, pos, y, captureOnly); } y = pos + 10; /* go right down */ if (y == 13 || y == 23 || y == 76 || y == 86) { gen_addMove(moves, pos, y, captureOnly); } break; } case PieceType::elephant: { int y = pos - 20; /* go left up */ if ((y == 2 || y == 6 || y == 18 || y == 22 || y == 47 || y == 51 || y == 63 || y == 67) && isEmpty(pos - 10)) { gen_addMove(moves, pos, y, captureOnly); } y = pos - 16; /* go right up */ if ((y == 2 || y == 6 || y == 22 || y == 26 || y == 47 || y == 51 || y == 67 || y == 71) && isEmpty(pos - 8)) { gen_addMove(moves, pos, y, captureOnly); } y = pos + 16; /* go left down */ if ((y == 18 || y == 22 || y == 38 || y == 42 || y == 63 || y == 67 || y == 83 || y == 87) && isEmpty(pos + 8)) { gen_addMove(moves, pos, y, captureOnly); } y = pos + 20; /* go right up */ if ((y == 22 || y == 26 || y == 38 || y == 42 || y == 67 || y == 71 || y == 83 || y == 87) && isEmpty(pos + 10)) { gen_addMove(moves, pos, y, captureOnly); } break; } case PieceType::cannon: { int col = pos % 9; /* * go left */ int f = 0; for (int y=pos - 1; y >= pos - col; y--) { if (isEmpty(y)) { if (f == 0 && !captureOnly) { gen_addMove(moves, pos, y, captureOnly); } continue; } f++; if (f == 2) { gen_addMove(moves, pos, y, captureOnly); break; } } /* * go right */ f = 0; for (int y=pos + 1; y < pos - col + 9; y++) { if (isEmpty(y)) { if (f == 0 && !captureOnly) { gen_addMove(moves, pos, y, captureOnly); } continue; } f++; if (f == 2) { gen_addMove(moves, pos, y, captureOnly); break; } } f = 0; for (int y=pos - 9; y >= 0; y -= 9) { /* go up */ if (isEmpty(y)) { if (f == 0 && !captureOnly) { gen_addMove(moves, pos, y, captureOnly); } continue; } f += 1 ; if (f == 2) { gen_addMove(moves, pos, y, captureOnly); break; } } f = 0; for (int y=pos + 9; y < 90; y += 9) { /* go down */ if (isEmpty(y)) { if (f == 0 && !captureOnly) { gen_addMove(moves, pos, y, captureOnly); } continue; } f += 1 ; if (f == 2) { gen_addMove(moves, pos, y, captureOnly); break; } } break; } case PieceType::rook: { int col = pos % 9; for (int y=pos - 1; y >= pos - col; y--) { /* go left */ gen_addMove(moves, pos, y, captureOnly); if (!isEmpty(y)) { break; } } for (int y=pos + 1; y < pos - col + 9; y++) { /* go right */ gen_addMove(moves, pos, y, captureOnly); if (!isEmpty(y)) { break; } } for (int y=pos - 9; y >= 0; y -= 9) { /* go up */ gen_addMove(moves, pos, y, captureOnly); if (!isEmpty(y)) { break; } } for (int y=pos + 9; y < 90; y += 9) { /* go down */ gen_addMove(moves, pos, y, captureOnly); if (!isEmpty(y)) { break; } } break; } case PieceType::horse: { int col = pos % 9; int y = pos - 11; int z = pos - 1; if (y >= 0 && col > 1 && isEmpty(z)) { gen_addMove(moves, pos, y, captureOnly); } y = pos - 19; z = pos - 9; if (y >= 0 && col > 0 && isEmpty(z)) { gen_addMove(moves, pos, y, captureOnly); } y = pos - 17; z = pos - 9; if (y >= 0 && col < 8 && isEmpty(z)) { gen_addMove(moves, pos, y, captureOnly); } y = pos - 7; z = pos + 1; if (y >= 0 && col < 7 && isEmpty(z)) { gen_addMove(moves, pos, y, captureOnly); } y = pos + 7; z = pos - 1; if (y < 90 && col > 1 && isEmpty(z)) { gen_addMove(moves, pos, y, captureOnly); } y = pos + 17; z = pos + 9; if (y < 90 && col > 0 && isEmpty(z)) { gen_addMove(moves, pos, y, captureOnly); } y = pos + 19; z = pos + 9; if (y < 90 && col < 8 && isEmpty(z)) { gen_addMove(moves, pos, y, captureOnly); } y = pos + 11; z = pos + 1; if (y < 90 && col < 7 && isEmpty(z)) { gen_addMove(moves, pos, y, captureOnly); } break; } case PieceType::pawn: { if ((side == Side::black && pos > 44) || (side == Side::white && pos < 45)) { int col = pos % 9; /* go left */ if (col > 0) { gen_addMove(moves, pos, pos - 1, captureOnly); } /* go right */ if (col < 8) { gen_addMove(moves, pos, pos + 1, captureOnly); } } if (side == Side::black) { /* go down */ if (pos < 81) { gen_addMove(moves, pos, pos + 9, captureOnly); } } else { /* go up */ if (pos > 8) { gen_addMove(moves, pos, pos - 9, captureOnly); } } break; } default: break; } } }
Didactic chess engines:
https://www.chessprogramming.org/Maksim_Korzh
Chess programming YouTube channel:
https://www.youtube.com/channel/UCB9-pr ... KKqDgXhsMQ
https://www.chessprogramming.org/Maksim_Korzh
Chess programming YouTube channel:
https://www.youtube.com/channel/UCB9-pr ... KKqDgXhsMQ
-
- Posts: 1437
- Joined: Wed Apr 21, 2010 4:58 am
- Location: Australia
- Full name: Nguyen Hong Pham
Re: Did anyone write a xiangqi chess engine?
Yes, so simple and straightforward, isn't it?maksimKorzh wrote: ↑Sun Jan 24, 2021 9:38 am Hold on a sec, so this code snippet relies on 9x10 array?
maksimKorzh wrote: ↑Sun Jan 24, 2021 9:38 am I just can't figure out how/where do you check for offboard squares?
You can do everything with IF-ELSE. Using mailbox margins is still required IF-ELSE to check offboards. For chess, that is a clever way to simplify the code generator and to reduce the number of IF-ELSE a bit. However, from my experience, it didn't save much for Xiangqi but bringing some disadvantages.
If you look closer to my code to generate moves for Rooks, for example:
Code: Select all
int col = pos % 9;
for (int y=pos - 1; y >= pos - col; y--) { /* go left */
gen_addMove(moves, pos, y, captureOnly);
if (!isEmpty(y)) {
break;
}
}
You can see the code for checking offboard squares is embedded inside the FOR-loop, i.e., "y >= pos - col". If that condition is false, you are outside of the board.
https://banksiagui.com
The most features chess GUI, based on opensource Banksia - the chess tournament manager
The most features chess GUI, based on opensource Banksia - the chess tournament manager