Conditional FEN generator?

Discussion of anything and everything relating to chess playing software and machines.

Moderator: Ras

Guenther
Posts: 4718
Joined: Wed Oct 01, 2008 6:33 am
Location: Regensburg, Germany
Full name: Guenther Simon

Conditional FEN generator?

Post by Guenther »

Does something like a conditional fen generator exist? A quick research revealed nothing.

Let's say as an example, you would be interested in all FENs with one side has 2P + 1R + 1N removed and the other its Q removed and this tool would generate all possible FENs with that combination.

My count is that there should be 28*4*2 combinations = 224 positions in this case. (28 = pawn tuples, 4 = R/N tuples, 2 = colour mirroring)

Guenther
Sven
Posts: 4052
Joined: Thu May 15, 2008 9:57 pm
Location: Berlin, Germany
Full name: Sven Schüle

Re: Conditional FEN generator?

Post by Sven »

Guenther wrote:Does something like a conditional fen generator exist? A quick research revealed nothing.

Let's say as an example, you would be interested in all FENs with one side has 2P + 1R + 1N removed and the other its Q removed and this tool would generate all possible FENs with that combination.

My count is that there should be 28*4*2 combinations = 224 positions in this case. (28 = pawn tuples, 4 = R/N tuples, 2 = colour mirroring)

Guenther
You don't really mean FEN's (which are representing concrete positions on the board) but combinations of present material, do you? There are certainly some orders of magnitude between "224" and the number of different positions with, say, six white pawns on the board (to take only a small part of the material from your example).
Guenther
Posts: 4718
Joined: Wed Oct 01, 2008 6:33 am
Location: Regensburg, Germany
Full name: Guenther Simon

Re: Conditional FEN generator?

Post by Guenther »

Sven Schüle wrote:
Guenther wrote:Does something like a conditional fen generator exist? A quick research revealed nothing.

Let's say as an example, you would be interested in all FENs with one side has 2P + 1R + 1N removed and the other its Q removed and this tool would generate all possible FENs with that combination.

My count is that there should be 28*4*2 combinations = 224 positions in this case. (28 = pawn tuples, 4 = R/N tuples, 2 = colour mirroring)

Guenther
You don't really mean FEN's (which are representing concrete positions on the board) but combinations of present material, do you? There are certainly some orders of magnitude between "224" and the number of different positions with, say, six white pawns on the board (to take only a small part of the material from your example).
Hmmm, I see there is a missunderstanding, I meant what I said, which is
all possible FENs with the given material conditions, BUT only for the starting position.
Somehow I wrongly thought that would be clear, no idea why.

Thus the first FENs would be like this (systematically) for my given example: 28 (pawn formations) * 4 (R/N variations) * 2 (colour change)

Code: Select all

rnb1kbnr/pppppppp/8/8/8/8/2PPPPPP/2BQKBNR w Kkq - 0 1
rnb1kbnr/pppppppp/8/8/8/8/1P1PPPPP/2BQKBNR w Kkq - 0 1
rnb1kbnr/pppppppp/8/8/8/8/1PP1PPPP/2BQKBNR w Kkq - 0 1
rnb1kbnr/pppppppp/8/8/8/8/1PPP1PPP/2BQKBNR w Kkq - 0 1
rnb1kbnr/pppppppp/8/8/8/8/1PPPP1PP/2BQKBNR w Kkq - 0 1
rnb1kbnr/pppppppp/8/8/8/8/1PPPPP1P/2BQKBNR w Kkq - 0 1
rnb1kbnr/pppppppp/8/8/8/8/1PPPPPP1/2BQKBNR w Kkq - 0 1

rnb1kbnr/pppppppp/8/8/8/8/P2PPPPP/2BQKBNR w Kkq - 0 1
rnb1kbnr/pppppppp/8/8/8/8/P1P1PPPP/2BQKBNR w Kkq - 0 1
rnb1kbnr/pppppppp/8/8/8/8/P1PP1PPP/2BQKBNR w Kkq - 0 1
rnb1kbnr/pppppppp/8/8/8/8/P1PPP1PP/2BQKBNR w Kkq - 0 1
rnb1kbnr/pppppppp/8/8/8/8/P1PPPP1P/2BQKBNR w Kkq - 0 1
rnb1kbnr/pppppppp/8/8/8/8/P1PPPPP1/2BQKBNR w Kkq - 0 1

rnb1kbnr/pppppppp/8/8/8/8/PP2PPPP/2BQKBNR w Kkq - 0 1
rnb1kbnr/pppppppp/8/8/8/8/PP1P1PPP/2BQKBNR w Kkq - 0 1
rnb1kbnr/pppppppp/8/8/8/8/PP1PP1PP/2BQKBNR w Kkq - 0 1
rnb1kbnr/pppppppp/8/8/8/8/PP1PPP1P/2BQKBNR w Kkq - 0 1
rnb1kbnr/pppppppp/8/8/8/8/PP1PPPP1/2BQKBNR w Kkq - 0 1

...
Sven
Posts: 4052
Joined: Thu May 15, 2008 9:57 pm
Location: Berlin, Germany
Full name: Sven Schüle

Re: Conditional FEN generator?

Post by Sven »

Now I understand. I don't know whether such a tool exists. So what would be the exact input parameters for that tool?
Guenther
Posts: 4718
Joined: Wed Oct 01, 2008 6:33 am
Location: Regensburg, Germany
Full name: Guenther Simon

Re: Conditional FEN generator?

Post by Guenther »

Sven Schüle wrote:Now I understand. I don't know whether such a tool exists. So what would be the exact input parameters for that tool?
At least for me it would be only the piece(s) which could be removed from each side from the starting position (except the Kings of course) and then iterating all FENs which have that material amount and a colour mirroring trigger.

It does not need to have an UI - let's say I just give input from the commandline and it asks for W and I just type what to remove for the
possible type of pieces and the same for B or something similar.

e.g. Q 2R 2B 2N 8P as max input for removing from one side, just as an idea, or even for both sides at once like Q r n 2p (original example)
with lowercase for Black and uppercase for White removing pieces... but that's just an implementation detail.
Colour mirroring would then just create the FENs for q R N 2P removed instead.

Guenther
Sven
Posts: 4052
Joined: Thu May 15, 2008 9:57 pm
Location: Berlin, Germany
Full name: Sven Schüle

Re: Conditional FEN generator?

Post by Sven »

I could send you a Windows executable for testing if you PM me your mail address. The C++ source code (compiled with old VS2010 express) has exactly 200 lines for which I needed exactly 2 hours :-) If anyone is interested I can also post the source code here.
Guenther
Posts: 4718
Joined: Wed Oct 01, 2008 6:33 am
Location: Regensburg, Germany
Full name: Guenther Simon

Re: Conditional FEN generator?

Post by Guenther »

Sven Schüle wrote:I could send you a Windows executable for testing if you PM me your mail address. The C++ source code (compiled with old VS2010 express) has exactly 200 lines for which I needed exactly 2 hours :-) If anyone is interested I can also post the source code here.
Sven, thanks for the effort I will PM you.

Guenther
Sven
Posts: 4052
Joined: Thu May 15, 2008 9:57 pm
Location: Berlin, Germany
Full name: Sven Schüle

Re: Conditional FEN generator?

Post by Sven »

Maybe this is the highest possible number of FENs here:

Code: Select all

fengen.exe -m R B N 4P r b n 4p | wc -l
627200
User avatar
Ajedrecista
Posts: 2215
Joined: Wed Jul 13, 2011 9:04 pm
Location: Madrid, Spain.

Re: Conditional FEN generator?

Post by Ajedrecista »

Hello Sven:
Sven Schüle wrote:Maybe this is the highest possible number of FENs here:

Code: Select all

fengen.exe -m R B N 4P r b n 4p | wc -l
627200
I would add that 0, 1 and 2 queens OTB (not only two) make the same number of 627200 possibilities.

The availability of the source code would be great! 200 lines seem a smart coding.

Thank you in advance.

Regards from Spain.

Ajedrecista.
Sven
Posts: 4052
Joined: Thu May 15, 2008 9:57 pm
Location: Berlin, Germany
Full name: Sven Schüle

Re: Conditional FEN generator?

Post by Sven »

Ajedrecista wrote:The availability of the source code would be great!

Code: Select all

// Usage example: fengen.exe [-m|--mirror] Q r n 2p
// See http://www.talkchess.com/forum/viewtopic.php?t=61003
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include <algorithm>
#include <vector>

// definitions for chess board representation

typedef int Color;
enum { White = 0, Black, Empty };

typedef int Piece;
enum { NoPiece = 0, Pawn, Knight, Bishop, Rook, Queen, King };

typedef int Square;
enum {
    A1 = 0,B1,C1,D1,E1,F1,G1,H1,
    A2,    B2,C2,D2,E2,F2,G2,H2,
    A3,    B3,C3,D3,E3,F3,G3,H3,
    A4,    B4,C4,D4,E4,F4,G4,H4,
    A5,    B5,C5,D5,E5,F5,G5,H5,
    A6,    B6,C6,D6,E6,F6,G6,H6,
    A7,    B7,C7,D7,E7,F7,G7,H7,
    A8,    B8,C8,D8,E8,F8,G8,H8,
    FF = 0xff
};

Color opponent(Color c) { return c ^ Black; }
Square makeSquare(int file, int rank) { return 8 * rank + file; }

struct Board {
    Color   color[64];
    Piece   piece[64];
    bool isPiece(Square s, Color c, Piece p) const { return color[s] == c && piece[s] == p; }
    void set(Square s, Color c, Piece p) { color[s] = c; piece[s] = p; }
    void clear(Square s) { set(s, Empty, NoPiece); }
    Board() { for (Square s = A1; s <= H8; s++) clear(s); }

    void printFEN()
    {
        int nEmpty = 0;
        for (int r = 7; r >= 0; r--) {
            for (int f = 0; f <= 7; f++) {
                Square s = makeSquare(f, r);
                if (color[s] == Empty) {
                    ++nEmpty;
                } else {
                    if (nEmpty > 0) {
                        fputc('1' + nEmpty - 1, stdout);
                        nEmpty = 0;
                    }
                    static char const pieceSym[] = ".pnbrqk";
                    if (color[s] == White) {
                        fputc(toupper(pieceSym[piece[s]]), stdout);
                    } else {
                        fputc(tolower(pieceSym[piece[s]]), stdout);
                    }
                    nEmpty = 0;
                }
            }
            if (r > 0) {
                if (nEmpty > 0) {
                    fputc('1' + nEmpty - 1, stdout);
                    nEmpty = 0;
                }
                fputc('/', stdout);
            }
        }
        fputs(" w ", stdout);
        if (isPiece(E1, White, King) && isPiece(H1, White, Rook)) fputc('K', stdout);
        if (isPiece(E1, White, King) && isPiece(A1, White, Rook)) fputc('Q', stdout);
        if (isPiece(E8, Black, King) && isPiece(H8, Black, Rook)) fputc('k', stdout);
        if (isPiece(E8, Black, King) && isPiece(A8, Black, Rook)) fputc('q', stdout);
        fputs(" - 0 1\n", stdout);
    }
};

// definitions needed to set up the initial position
// usually more simple than that but we need to iterate over each group of pieces of same type

struct PieceInitDescr {
    int     nPieces;
    Square  initSqr[8];
};

PieceInitDescr pieceInitDescr[2][1+6] = {
    {
        { 0, { FF,FF,FF,FF,FF,FF,FF,FF } },
        { 8, { A2,B2,C2,D2,E2,F2,G2,H2 } },
        { 2, { B1,G1,FF,FF,FF,FF,FF,FF } },
        { 2, { C1,F1,FF,FF,FF,FF,FF,FF } },
        { 2, { A1,H1,FF,FF,FF,FF,FF,FF } },
        { 1, { D1,FF,FF,FF,FF,FF,FF,FF } },
        { 1, { E1,FF,FF,FF,FF,FF,FF,FF } },
    },
    {
        { 0, { FF,FF,FF,FF,FF,FF,FF,FF } },
        { 8, { A7,B7,C7,D7,E7,F7,G7,H7 } },
        { 2, { B8,G8,FF,FF,FF,FF,FF,FF } },
        { 2, { C8,F8,FF,FF,FF,FF,FF,FF } },
        { 2, { A8,H8,FF,FF,FF,FF,FF,FF } },
        { 1, { D8,FF,FF,FF,FF,FF,FF,FF } },
        { 1, { E8,FF,FF,FF,FF,FF,FF,FF } },
    },
};

// data related to command line parameters

int missing[2][1+6] = {
    { 0, 0, 0, 0, 0, 0, 0 },
    { 0, 0, 0, 0, 0, 0, 0 },
};

bool mirror = false;

template <bool Mirror>
void enumerate(Board & b, Color c, Piece p)
{
    Color cMiss = (Mirror ? opponent(c) : c);
    Color cStop = (Mirror ? White : Black);

    PieceInitDescr const & d = pieceInitDescr[c][p];

    // setup initial pieces of given color and type
    for (int i = 0; i < d.nPieces; i++) {
        b.set(d.initSqr[i], c, p);
    }

    if (p == King && c == cStop) {
        b.printFEN();
    } else {
        // generate all permutations of missing pieces for the given color and piece type
        int nPresent = d.nPieces - missing[cMiss][p];
        std::vector<bool> v(d.nPieces);
        std::fill(v.end() - nPresent, v.end(), true);
        do {
            // remove missing pieces
            for (int i = 0; i < d.nPieces; i++) {
                if (!v[i]) {
                    b.clear(d.initSqr[i]);
                }
            }
            // recursive call
            Color cNext = (p == King) ? opponent(c) : c;
            Piece pNext = (p == King) ? Pawn : p + 1;
            enumerate<Mirror>(b, cNext, pNext);
            // restore removed pieces
            for (int i = 0; i < d.nPieces; i++) {
                if (!v[i]) {
                    b.set(d.initSqr[i], c, p);
                }
            }
        } while (std::next_permutation(v.begin(), v.end()));
    }

    // clear initial pieces
    for (int i = 0; i < d.nPieces; i++) {
        b.clear(d.initSqr[i]);
    }
}

int main(int argc, char * argv[])
{
    // scan parameters (illegal parameters are ignored for simplicity)
    for (int i = 1; i < argc; i++) {
        char const * arg = argv[i];
        if (strcmp(arg, "-m") == 0 || strcmp(arg, "--mirror") == 0) {
            mirror = true;
        } else
        if (strlen(arg) <= 2) {
            int number  = (strlen(arg) == 1) ? 1         : arg[0] + 1 - '1';
            char p      = (strlen(arg) == 1) ? arg[0]    : arg[1];
            Color color = (p == toupper(p)) ? White : Black;
            Piece piece = NoPiece;
            switch (tolower(p)) {
                case 'p': piece = Pawn;     break;
                case 'n': piece = Knight;   break;
                case 'b': piece = Bishop;   break;
                case 'r': piece = Rook;     break;
                case 'q': piece = Queen;    break;
                // king must not be missing
                default: break;
            }
            if (piece != NoPiece && number >= 1 && number <= pieceInitDescr[color][piece].nPieces) {
                missing[color][piece] = number;
            }
        }
    }

    // enumerate combinations of missing pieces
    Board b;
    enumerate<false>(b, White, Pawn);
    if (mirror) {
        enumerate<true>(b, Black, Pawn);
    }
    return 0;
}