summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authortomsmeding <tom.smeding@gmail.com>2018-03-12 12:26:10 +0100
committertomsmeding <tom.smeding@gmail.com>2018-03-12 12:26:10 +0100
commit485228f8e01fef40a79cff4c5631388188675df6 (patch)
tree8a130dff2082f92c2e389eff358138f2e4de7fd1
parent0369c84bcaea4a1e3c7e41be4ece2c815ab487e3 (diff)
Check mate
-rw-r--r--board.cpp79
-rw-r--r--board.h8
2 files changed, 80 insertions, 7 deletions
diff --git a/board.cpp b/board.cpp
index 0ac5348..b72ac5f 100644
--- a/board.cpp
+++ b/board.cpp
@@ -293,18 +293,76 @@ void Board::apply(const Move &mv) {
lastTarget = mv.to;
}
-bool Board::isValid(const Move &mv) {
+bool Board::isValid(const Move &mv) const {
assert(mv.castle == 0);
if (colour(at(mv.from)) != onTurn) return false;
Board B(*this);
B.apply(mv);
- // cerr << "after applying:" << endl << B << endl;
- // cerr << subsequents()[27] << endl;
- // cerr << (B == subsequents()[27]) << endl;
+ bool found = false;
for (const Board &B2 : subsequents()) {
- if (B == B2) return true;
+ if (B == B2) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) return false;
+ switch (B.checkCheck(onTurn)) {
+ case CheckResult::check:
+ case CheckResult::checkmate:
+ return false;
+ default:
+ return true;
+ }
+}
+
+CheckResult Board::checkCheck(int player) const {
+ // First check 'check' (p), then check if we have 'check' after any move (q).
+ // p | q | Result
+ // 0 | 0 | safe
+ // 0 | 1 | stalemate
+ // 1 | 0 | check
+ // 1 | 1 | checkmate
+
+
+ // Check 'check' by switching onTurn and seeing if the king can be taken
+ bool haveP = false;
+ Board B1(*this);
+ B1.onTurn = !player;
+ for (const Board &B2 : B1.subsequents()) {
+ if (B2.pieceScore[B1.onTurn] >= worth(KING)) {
+ haveP = true;
+ break;
+ }
+ }
+
+ // Then check if we have 'check' after any move
+ bool haveQ = true;
+ B1.onTurn = player;
+ for (const Board &B2 : subsequents()) {
+ bool checkNow = false;
+ for (const Board &B3 : B2.subsequents()) {
+ if (B3.pieceScore[B2.onTurn] >= worth(KING)) {
+ checkNow = true;
+ break;
+ }
+ }
+ if (!checkNow) {
+ haveQ = false;
+ break;
+ }
+ }
+
+ if (haveP) {
+ if (haveQ) return CheckResult::checkmate;
+ else return CheckResult::check;
+ } else {
+ if (haveQ) return CheckResult::stalemate;
+ else return CheckResult::safe;
}
- return false;
+}
+
+static const char* playerName(int player) {
+ return &"WHITE\0BLACK"[player * 6];
}
ostream& operator<<(ostream &os, const Board &B) {
@@ -320,9 +378,16 @@ ostream& operator<<(ostream &os, const Board &B) {
}
if (y == 0) {
os << " ps[W] = " << B.pieceScore[WHITE];
- os << " onTurn = " << (&"WHITE\0BLACK"[B.onTurn * 6]);
+ os << " onTurn = " << playerName(B.onTurn);
} else if (y == 1) {
os << " ps[B] = " << B.pieceScore[BLACK];
+ } else if (y == 2) {
+ switch (B.checkCheck(B.onTurn)) {
+ case CheckResult::safe: break;
+ case CheckResult::check: os << " " << playerName(B.onTurn) << " IN CHECK"; break;
+ case CheckResult::checkmate: os << " " << playerName(B.onTurn) << " CHECKMATED."; break;
+ case CheckResult::stalemate: os << " " << playerName(B.onTurn) << " STALEMATED."; break;
+ }
}
os << '\n';
}
diff --git a/board.h b/board.h
index eb50917..6b17d53 100644
--- a/board.h
+++ b/board.h
@@ -17,6 +17,10 @@ const int EMPTY = 0, PAWN = 1, ROOK = 2, KNIGHT = 3, BISHOP = 4, KING = 5, QUEEN
// ...
// WHITE WHITE WHITE y = 7
+enum class CheckResult {
+ safe, check, checkmate, stalemate
+};
+
#define IDX(x_, y_) (8 * (y_) + (x_))
@@ -59,6 +63,10 @@ public:
bool isValid(const Move &mv) const; // SLOW
+ // SLOW; Only detects anything for the given player.
+ // Assumes no king has been taken yet.
+ CheckResult checkCheck(int player) const;
+
friend bool operator==(const Board &B1, const Board &B2);
};