Comments/Ratings for a Single Item
To Fergus Duniho: you are obviously unsure on the grade of distinctness between valid CRC arrays and the GC starting position. So let us do a historic approach and try to calculate the distance between GC and historic 10x8 starting arrays as from Carrera, Bird or Capablanca. I think that there are more than three reported arrays from those people. When it has been possible to patent GC being only slightly different to those positions, it should be sufficient to demand only the smallest there occurring distance. Comparing the GC array 'RNBQCKABNR' to one reported as from Bird 'RNBCQKABNR' there is a Hamming distance of only two. But I am not sure, if this Bird's array has been specified that way - I am missing still the original source. If the smallest distance indeed should be greater than three, the code I have supplied has to be changed appropriately. May be variant experts could help to solve that question doubtlessly.
//======================================== // Valid CRC / Chess960 Position generator //======================================== // Reference Implementation, (C) 2005 by // Reinhard Scharnagl, Munich, Germany //---------------------------------------- // Correction 2005-Feb-28 (GC-Nearness) //======================================== #include < string.h> #include < stdio.h> #define TXT_LIM 160 static char FenZone[TXT_LIM]; // insert a symbol into FEN-String // ------------------------------- // color could be: // col < 0 => not specified // col == 0 => bright square // col == 1 => dark square void PlaceIntoFEN (int cntFree, char symbol, int fieldColor) { for (int pos = 0, free = 0; ; ++pos) { if (fieldColor < 0 || ((fieldColor ^ pos) & 1)) { if (!FenZone[pos] && cntFree == free++) { FenZone[pos] = symbol; break; } } } } // generating of FEN strings // ------------------------- // nr could be // nr >= 0 creating Chess960 position (1 ... 960) // nr < 0 creating CRC position (1 ... 48000) const char *GetFen(int nr) { // knight distributions over 5 free squares static const int knight_pos[10] = { 3, // xx--- (binary encoded) 5, // x-x-- 9, // x--x- 17, // x---x 6, // -xx-- 10, // -x-x- 18, // -x--x 12, // --xx- 20, // --x-x 24 // ---xx }; // clear the working area int bit, pos = TXT_LIM; while (--pos >= 0) { FenZone[pos] = '\0'; } // test whether CRC is requested bool isCRC = (nr <= 0); if (isCRC) { nr = -nr; bool q_first = ((nr % 2) != 0); nr /= 2; PlaceIntoFEN(nr % 5, q_first ? 'q' : 'a', 0); nr /= 5; PlaceIntoFEN(nr % 5, q_first ? 'a' : 'q', 1); nr /= 5; } PlaceIntoFEN(nr % 4, 'b', 0); nr /= 4; PlaceIntoFEN(nr % 4, 'b', 1); nr /= 4; PlaceIntoFEN(nr % 6, isCRC ? 'c' : 'q', -1); nr /= 6; pos = knight_pos[nr % 10]; for (bit = 5; --bit >= 0; ) { if ((pos & (1 << bit)) != 0) PlaceIntoFEN(bit, 'n', -1); } PlaceIntoFEN(2, 'r', -1); PlaceIntoFEN(1, 'k', -1); PlaceIntoFEN(0, 'r', -1); int width = isCRC ? 10 : 8; char *pC = &FenZone[width]; *pC++ = '/'; for (pos = width; --pos >= 0; ) { *pC++ = 'p'; } for (pos = 4; --pos >= 0; ) { *pC++ = '/'; if (width >= 10) { *pC++ = '1'; } *pC++ = (char)('0' + width % 10); } *pC++ = '/'; for (pos = width; --pos >= 0; ) { *pC++ = 'P'; } *pC++ = '/'; for (pos = 0; pos < width; ++pos) { *pC++ = FenZone[pos] ^ ('a'^'A'); } strcpy(pC, ' w KQkq - 0 1'); return FenZone; } // check if FEN is valid for CRC // ----------------------------- bool IsValidCRC(const char *pFen) { // to be avoided GC position static const char *gcArray = 'rnbqckabnr'; // pawn covering pieces (like a rook) static const char *covNear = 'rcqk'; // pawn covering pieces (like a bishop) static const char *covDiag = 'baqk'; // pawn covering pieces (like a knight) static const char *covDist = 'nac'; int size = (int)(strchr(pFen, '/') - pFen); int diff = 0; for (int n = size; --n >= 0; ) { // different to GC? if (pFen[n] != gcArray[n]) { ++diff; } // unprotected pawns? if (strchr(covNear, pFen[n])) continue; if ((n+1) < size && strchr(covDiag, pFen[n+1])) continue; if ((n-1) >= 0 && strchr(covDiag, pFen[n-1])) continue; if ((n+2) < size && strchr(covDist, pFen[n+2])) continue; if ((n-2) >= 0 && strchr(covDist, pFen[n-2])) continue; return false; } // GC-near position? if (diff < 3 && size == (int)strlen(gcArray)) { return false; } return true; } // test output // ----------- int main(void) { puts('\nfirst Chess960 positions'); for (int nrFRC = 0; ++nrFRC <= 10; ) { printf('(%03d) %s\n', nrFRC, GetFen(nrFRC)); } puts('\nfirst CRC positions'); int cntValid = 0; for (int nrCRC = 0; ++nrCRC <= 48000; ) { const char *pFEN = GetFen(-nrCRC); bool valid = IsValidCRC(pFEN); if (nrCRC <= 32) { printf('(%05d %s) %s\n', nrCRC, valid ? 'ok' : '--', pFEN); } if (valid) { ++cntValid; } } printf('\n%d valid CRC arrays\n', cntValid); return 0; }
To Mark Thompson: three always is a good number. We have so much possible positions in CRC, so it does not hurt to skip some to avoid any conflicts with Gothic Chess. Live and let live. To Fergus Duniho: it seems as if you would use a very complex method to detect invalid starting positions. I will add a more simple method in short to the reference code I have posted here yesterday. Thus one will be able to see, that generating valid CRC positions only is neither a run time problem nor too complex to be programmed.
//===================================== // CRC / Chess960 Position Generator //===================================== // reference implementation (C) 2005 by // Reinhard Scharnagl, Munich, Germany //===================================== #include < string.h> #include < stdio.h> #define TXT_LIM 160 static char FenZone[TXT_LIM]; // insert a symbol into FEN-String // ------------------------------- // color could be: // col < 0 => not specified // col == 0 => bright square // col == 1 => dark square void PlaceIntoFEN (int cntFree, char symbol, int fieldColor) { for (int pos = 0, free = 0; ; ++pos) { if (fieldColor < 0 || ((fieldColor ^ pos) & 1)) { if (!FenZone[pos] && cntFree == free++) { FenZone[pos] = symbol; break; } } } } // generating of FEN strings // ------------------------- // nr could be // nr >= 0 creating Chess960 position (1 ... 960) // nr < 0 creating CRC position (1 ... 48000) const char *GetFen(int nr) { // knight distributions over 5 free squares static const int knight_pos[10] = { 3, // xx--- (binary encoded) 5, // x-x-- 9, // x--x- 17, // x---x 6, // -xx-- 10, // -x-x- 18, // -x--x 12, // --xx- 20, // --x-x 24 // ---xx }; // clear the working area int bit, pos = TXT_LIM; while (--pos >= 0) { FenZone[pos] = '\0'; } // test whether CRC is requested bool istCRC = (nr <= 0); if (istCRC) { nr = -nr; bool q_first = ((nr % 2) != 0); nr /= 2; PlaceIntoFEN(nr % 5, q_first ? 'q' : 'a', 0); nr /= 5; PlaceIntoFEN(nr % 5, q_first ? 'a' : 'q', 1); nr /= 5; } PlaceIntoFEN(nr % 4, 'b', 0); nr /= 4; PlaceIntoFEN(nr % 4, 'b', 1); nr /= 4; PlaceIntoFEN(nr % 6, istCRC ? 'c' : 'q', -1); nr /= 6; pos = knight_pos[nr % 10]; for (bit = 5; --bit >= 0; ) { if ((pos & (1 << bit)) != 0) PlaceIntoFEN(bit, 'n', -1); } PlaceIntoFEN(2, 'r', -1); PlaceIntoFEN(1, 'k', -1); PlaceIntoFEN(0, 'r', -1); int width = istCRC ? 10 : 8; char *pC = &FenZone[width]; *pC++ = '/'; for (pos = width; --pos >= 0; ) { *pC++ = 'p'; } for (pos = 4; --pos >= 0; ) { *pC++ = '/'; *pC++ = (char)('0' + width % 10); } *pC++ = '/'; for (pos = width; --pos >= 0; ) { *pC++ = 'P'; } *pC++ = '/'; for (pos = 0; pos < width; ++pos) { *pC++ = FenZone[pos] ^ ('a'^'A'); } strcpy(pC, ' w KQkq - 0 1'); return FenZone; } // test output int main(void) { puts('first Chess960 positions'); for (int nrFRC = 0; ++nrFRC <= 5; ) { puts(GetFen(nrFRC)); } puts('first CRC positions'); for (int nrCRC = 0; ++nrCRC <= 5; ) { puts(GetFen(-nrCRC)); } return 0; }
Why does each Pawn need to be defended at the initial set-up? This seems to be an arbitrary rule. There are many good Chess games where each and every Pawn is not defended at the start. In fact, these un-defended Pawns can create a nice area of early contention in play. Is there an actual 'flawed' setup, resulting in the loss of the game for one or the other player?
Fischer Random Chess has the 960 legal starting positions numbered, and has the details on how to find a position from it's number, and how to find the number based on the position. Capablanca Random Chess could benefit from such a system. Besides making it easier to identify starting positions, it would also solve Fergus' present dilema. If a position can be determined from a position number, all that would be required is generation a random number in the valid range. For a good description of how FRC identifies positions by number, see: http://frcec.tripod.com/fischerrandomchessstartingpositions/
Reinhard, I've worked up an example with two crossed spears and a pair of wings flanking a halo. You should be able to view it below: http://users3.ev1.net/~llsmith/home/angel_w.gif
Just a small aesthetic observation about the graphic for the Archangel. Swords being short-range weapons, angels are also known to carry spears which have longer range. To carry over the motif from the Centaur, it could be a horseshoe with two crossed spears. Or the angelic theme might be further emphasized with a pair of wings and two crossed spears.
To Greg Strong: of course you are right with your historical hints. There might be some remarks to be added in the CRC description. The CRC text should be extended, if there would be enough interested readers. To Greg Strong and David Paulowich: indeed there are more traditional names for C (Chancellor) and A (Archbishop). But those names do not correspond to the pieces: nor to their gaits nor to their symbols. I have tried to design more intuitive gait related symbols and noticed, that the names would not be helpful for newcomers to the Capablanca extended piece set. So I proposed names (partially already used differently in other context) to enhance the readability of CRC board positions to interested people. But that approach is only a suggestion, carefully keeping the same initial letters e.g. to stay compatible within X-FEN. To all posters here at CRC until now: thank you for your interest and encouraging words!
Nice to see you moving forward with your dream. Best regards!
Very nice! The author has done an excellent job of defining a Fischer randomization system for Capablanca's Chess (actually this piece mix goes back to the 1600s with D. Pietro Carrera -- see Carrera's Chess.) It is obvious to me that the design has been carefully considered from both a game-designer's perspective and a software developer's perspective.
I'm not sure I like the idea of renaming the pieces, though. There are already too many different names for these pieces, and I think the goal should be to standardize the names, and I believe Capablanca's names of Archbishop and Chancellor are probably the best choices.
25 comments displayed
Permalink to the exact comments currently displayed.