How can I get the following compiled on UVA?
- by Michael Tsang
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;
}