开发者

How can I get the following compiled on UVA?

Note the comment below. It cannot compiled on UVA because of a bug in GCC.

#include <cstdio>
#include <cstring>
#include <cctype>
#include <map>
#include <stdexcept>

class Board {
public:
    bool read(FILE *);
    enum Colour {none, white, black};
    Colour check() const;
private:
    struct Index {
            size_t x;
            size_t y;
            Index &operator+=(const Index &) throw(std::range_error);
            Index operator+(const Index &) const throw(std::range_error);
    };
    const static std::size_t size = 8;
    char data[size][size];
    // Cannot be compiled on GCC 4.1.2 due to GCC bug 29993
    // http://gcc.gnu.org/bugzilla/show_bug.cgi?id=29993
    typedef bool CheckFunction(Colour, const Index &) const;
    CheckFunction pawn, knight, bishop, king, rook;

    bool queen(const Colour c, const Index &location) const {
            return rook(c, location) || bishop(c, location);
    }

    static char get_king(Colour c) {
            return c == white ? 'k' : 'K';
    }

    template<std::size_t n>
    bool check_consecutive(Colour c, const Index &location, const Index (&offsets)[n]) const {
            for(const Index *p = offsets; p != (&offsets)[1]; ++p) {
                    try {
                            Index target = location + *p;
                            for(; data[target.x][target.y] == '.'; target += *p) {
                            }
                            if(data[target.x][target.y] == get_king(c)) return true;
                    } catch(std::range_error &) {
                    }
            }
            return false;
    }

    template<std::size_t n>
    bool check_distinct(Colour c, const Index &location, const Index (&offsets)[n]) const {
            for(const Index *p = offsets; p != (&offsets)[1]; ++p) {开发者_如何转开发
                    try {
                            Index target = location + *p;
                            if(data[target.x][target.y] == get_king(c)) return true;
                    } catch(std::range_error &) {
                    }
            }
            return false;
    }
};

int main() {
    Board board;
    for(int d = 1; board.read(stdin); ++d) {
            Board::Colour c = board.check();
            const char *sp;
            switch(c) {
            case Board::black:
                    sp = "white";
                    break;
            case Board::white:
                    sp = "black";
                    break;
            case Board::none:
                    sp = "no";
                    break;
            }
            std::printf("Game #%d: %s king is in check.\n", d, sp);
            std::getchar(); // discard empty line
    }
}

bool Board::read(FILE *f) {
    static const char empty[] =
            "........"
            "........"
            "........"
            "........"
            "........"
            "........"
            "........"
            "........";     // 64 dots
    for(char (*p)[size] = data; p != (&data)[1]; ++p) {
            std::fread(*p, size, 1, f);
            std::fgetc(f);  // discard new-line
    }
    return std::memcmp(empty, data, sizeof data);
}

Board::Colour Board::check() const {
    std::map<char, CheckFunction Board::*> fp;
    fp['P'] = &Board::pawn;
    fp['N'] = &Board::knight;
    fp['B'] = &Board::bishop;
    fp['Q'] = &Board::queen;
    fp['K'] = &Board::king;
    fp['R'] = &Board::rook;
    for(std::size_t i = 0; i != size; ++i) {
            for(std::size_t j = 0; j != size; ++j) {
                    CheckFunction Board::* p = fp[std::toupper(data[i][j])];
                    if(p) {
                            Colour ret;
                            if(std::isupper(data[i][j])) ret = white;
                            else ret = black;
                            if((this->*p)(ret, (Index){i, j}/* C99 extension */)) return ret;
                    }
            }
    }
    return none;
}

bool Board::pawn(const Colour c, const Index &location) const {
    const std::ptrdiff_t sh = c == white ? -1 : 1;
    const Index offsets[] = {
            {sh, 1},
            {sh, -1}
    };
    return check_distinct(c, location, offsets);
}

bool Board::knight(const Colour c, const Index &location) const {
    static const Index offsets[] = {
            {1, 2},
            {2, 1},
            {2, -1},
            {1, -2},
            {-1, -2},
            {-2, -1},
            {-2, 1},
            {-1, 2}
    };
    return check_distinct(c, location, offsets);
}

bool Board::bishop(const Colour c, const Index &location) const {
    static const Index offsets[] = {
            {1, 1},
            {1, -1},
            {-1, -1},
            {-1, 1}
    };
    return check_consecutive(c, location, offsets);
}

bool Board::rook(const Colour c, const Index &location) const {
    static const Index offsets[] = {
            {1, 0},
            {0, -1},
            {0, 1},
            {-1, 0}
    };
    return check_consecutive(c, location, offsets);
}

bool Board::king(const Colour c, const Index &location) const {
    static const Index offsets[] = {
            {-1, -1},
            {-1, 0},
            {-1, 1},
            {0, 1},
            {1, 1},
            {1, 0},
            {1, -1},
            {0, -1}
    };
    return check_distinct(c, location, offsets);
}

Board::Index &Board::Index::operator+=(const Index &rhs) throw(std::range_error) {
    if(x + rhs.x >= size || y + rhs.y >= size) throw std::range_error("result is larger than size");
    x += rhs.x;
    y += rhs.y;
    return *this;
}

Board::Index Board::Index::operator+(const Index &rhs) const throw(std::range_error) {
    Index ret = *this;
    return ret += rhs;
}


The code that does not compile is simply a short-cut for declaring pawn, knight, bishop, king, and rook as being constant functions that take a Colour and const reference to a Index, return a bool. Simply replace:

typedef bool CheckFunction(Colour, const Index &) const;
    CheckFunction pawn, knight, bishop, king, rook;

With:

bool pawn(Colour, const Index &) const;
bool knight(Colour, const Index &) const;
bool bishop(Colour, const Index &) const;
bool king(Colour, const Index &) const;
bool rook(Colour, const Index &) const;

Frankly I am surprised that someone was so lazy that they used the former rather than the latter. IMHO, the latter is significantly more readable than the former, and the latter is not that much longer.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜