Пример #1
0
static
void
MoveAndReplaceTarget(USER_DATA *ud, BOARD b, int x, int y, int dx, int dy)
{
	PIECE *p = GetPieceAt(b, x, y);
	PIECE old_p = *p;

	// clear drawing at old location
	LvzActivate(ud, NULL, p->color, p->type, x, y, false);

	// unset target piece
	PIECE *t = GetPieceAt(b, dx, dy);
	if (t->type != TYPE_NONE) {
		LvzActivate(ud, NULL, t->color, t->type, dx, dy, false);
	}

	// clear old location
	SetPieceAt(b, x, y, COLOR_NONE, TYPE_NONE);

	// copy old piece to new location
	*t = old_p;

	// draw it
	LvzActivate(ud, NULL, t->color, t->type, dx, dy, true);
}
Пример #2
0
/*
 * 'c' is the attackers color.
 * kingx and kingy is the target king location.
 */
static
bool
IsCheckmatedBy(BOARD b, COLOR c, int kingx, int kingy)
{
	struct timeval tv;
	gettimeofday(&tv, NULL);

	COLOR defender = GetOppositeColor(c);

	PIECE *p;
	// for each piece on the board that is defending
	for (int x = 0; x < 8; ++x)
	for (int y = 0; y < 8; ++y) {
		p = GetPieceAt(b, x, y);
		if (p->color != defender) {
			continue;
		}

		// for each tile on the board, see if that piece can move there
		for (int j = 0; j < 8; ++j)
		for (int i = 0; i < 8; ++i) {
			if (PieceCanAttack(b, p->color, p->type, x, y, i, j) == true &&
			    GetPieceAt(b, i, j)->color != p->color) {
				PIECE old_p = *GetPieceAt(b, x, y);
				PIECE old_t = *GetPieceAt(b, i, j);

				// temporarily make the move
				SetPieceAt(b, x, y, COLOR_NONE, TYPE_NONE);
				SetPieceAt(b, i, j, old_p.color, old_p.type);

				// see if the move cancels check
				bool is_mate = true;
				int kx, ky;
				FindKing(b, defender, &kx, &ky);
				if (IsCoordAttackedBy(b, c, kx, ky) == false) {
					is_mate = false;
				}
				
				// revert the pieces
				SetPieceAt(b, x, y, old_p.color, old_p.type);
				SetPieceAt(b, i, j, old_t.color, old_t.type);

				if (is_mate == false) {
					struct timeval tv2;
					gettimeofday(&tv2, NULL);
					LogFmt(OP_MOD, "Checkmate Calculation: %lu.%06lu", tv2.tv_sec - tv.tv_sec, tv2.tv_usec - tv.tv_usec);
					return false;
				}
			}
		}
	}

	struct timeval tv2;
	gettimeofday(&tv2, NULL);

	LogFmt(OP_MOD, "Checkmate Calculation: %lu.%06lu", tv2.tv_sec - tv.tv_sec, tv2.tv_usec - tv.tv_usec);

	return true;
}
Пример #3
0
static
void
LvzDrawAll(USER_DATA *ud, PLAYER *p, bool show)
{
	PIECE *piece;
	for (int j = 0; j < 8; ++j)
	for (int i = 0; i < 8; ++i) {
		piece = GetPieceAt(ud->board, i, j);
		if (piece->type == TYPE_NONE) {
			continue;
		}

		LvzActivate(ud, p, piece->color, piece->type, i, j, show);
	}
}
Пример #4
0
static
bool
IsCoordAttackedBy(BOARD b, COLOR c, int x, int y)
{
	PIECE *p;
	for (int j = 0; j < 8; ++j) {
	for (int i = 0; i < 8; ++i) {
		p = GetPieceAt(b, i, j);
		if (p->color == c &&
		    PieceCanAttack(b, c, p->type, i, j, x, y) == true) {
			return true;
		}
	}
	}
	return false;
}
Пример #5
0
/*
 * This function is no longer necessary with LVZ graphics but
 * may still be useful for debugging at some point.
 */
static
void
DrawBoard(BOARD b)
{
	text display
	char line[128];
	int linei = 0;

	ArenaMessage("+---------------------+");
	ArenaMessage("|   a b c d e f g h   |");

	PIECE *p;
	for (int y = 7; y >= 0; --y) {
		line[linei++] = '|';
		line[linei++] = ' ';
		line[linei++] = '1' + y;
		line[linei++] = '|';
		for (int x = 0; x < 8; ++x) {
			p = GetPieceAt(b, x, y);
			char c;
			if (p->type == TYPE_NONE) {
				c = ' ';
			} else {
				if (p->color == COLOR_WHITE) {
					c = p->type;
				} else {
					c = p->type + ('a' - 'A');
				}
			}
			line[linei++] = c;
			line[linei++] = '|';
		}
		line[linei++] = '1' + y;
		line[linei++] = ' ';
		line[linei++] = '|';
		line[linei] = '\0';
		linei = 0;

		ArenaMessage("|  +-+-+-+-+-+-+-+-+  |");
		ArenaMessage(line);
	}
	ArenaMessage("|  +-+-+-+-+-+-+-+-+  |");
	ArenaMessage("|   a b c d e f g h   |");
	ArenaMessage("|_____________________|");
}
Пример #6
0
static
void
FindKing(BOARD b, COLOR c, int *x, int *y)
{
	*x = 0;
	*y = 0;

	PIECE *p;
	for (int i = 0; i < 8; ++i) {
		for (int j = 0; j < 8; ++j) {
			p = GetPieceAt(b, j, i);
			if (p->type == TYPE_KING && p->color == c) {
				*x = j;
				*y = i;
			}
		}
	}
}
Пример #7
0
void Board::Print() const {
    bool colour_toggle = false;
    char rank = 8;
    for (; rank >= 1; rank--) {
        std::cout << char('0' + rank) << " ";
        char file = 'A';
        for (; file <= 'H'; file++) {
            Piece p = GetPieceAt(rank, file);
            if (p.GetType() == Piece::None) {
                std::cout << (colour_toggle ? '.' : ' ');

            }
            else {
                std::cout << p.GetText();
            }
            colour_toggle = !colour_toggle;
            std::cout << ' ';
        }
        std::cout << std::endl;
        colour_toggle = !colour_toggle;

    }
    std::cout << "  A B C D E F G H " << std::endl;
}
Пример #8
0
/*
 * TODO: rewrite this to remove duplicated code
 */
static
char*
TryCastle(USER_DATA *ud, COLOR c, int x, int y, int dx, int dy)
{
	BOARD b = ud->board;
	// coordinates were already verified by IsCastleMove()

	COLOR opp = GetOppositeColor(c);
	if (IsCoordAttackedBy(b, opp, x, y) == true) {
		return "Can't castle out of check";
	}

	if (c == COLOR_WHITE) {
		if (dx == 6) {
			if (IsCoordAttackedBy(b, opp, 5, 0) ||
			    IsCoordAttackedBy(b, opp, 6, 0)) {
				return "Can't castle through or into check";
			}
			if (GetPieceAt(b, 5, 0)->type != TYPE_NONE ||
			    GetPieceAt(b, 6, 0)->type != TYPE_NONE) {
				return "Can't castle through pieces";
			}
			if (GetPieceAt(b, 7, 0)->type != TYPE_ROOK ||
			    GetPieceAt(b, 7, 0)->color != COLOR_WHITE) {
				return "No rook";
			}

			MoveAndReplaceTarget(ud, b, x, y, dx, dy);
			MoveAndReplaceTarget(ud, b, 7, 0, 5, 0);

			ArenaMessageFmt("%s (%s) Moves: Castle kingside",
			    GetPlayerName(ud, c), GetColorText(c));

			return NULL;
		} else if (dx == 2) {
			// castle queenside
			if (IsCoordAttackedBy(b, opp, 2, 0) ||
			    IsCoordAttackedBy(b, opp, 3, 0)) {
				return "Can't castle through or into check";
			}
			if (GetPieceAt(b, 1, 0)->type != TYPE_NONE ||
			    GetPieceAt(b, 2, 0)->type != TYPE_NONE ||
			    GetPieceAt(b, 3, 0)->type != TYPE_NONE) {
				return "Can't castle through pieces";
			}
			if (GetPieceAt(b, 0, 0)->type != TYPE_ROOK ||
			    GetPieceAt(b, 0, 0)->color != COLOR_WHITE) {
				return "No rook";
			}

			MoveAndReplaceTarget(ud, b, x, y, dx, dy);
			MoveAndReplaceTarget(ud, b, 0, 0, 3, 0);

			ArenaMessageFmt("%s (%s) Moves: Castle queenside",
			    GetPlayerName(ud, c), GetColorText(c));

			return NULL;
		}
	} else if (c == COLOR_BLACK) {
		if (dx == 6) {
			// castle kingside
			if (IsCoordAttackedBy(b, opp, 5, 7) ||
			    IsCoordAttackedBy(b, opp, 6, 7)) {
				return "Can't castle through or into check";
			}
			if (GetPieceAt(b, 5, 7)->type != TYPE_NONE ||
			    GetPieceAt(b, 6, 7)->type != TYPE_NONE) {
				return "Can't castle through pieces";
			}
			if (GetPieceAt(b, 7, 7)->type != TYPE_ROOK ||
			    GetPieceAt(b, 7, 7)->color != COLOR_BLACK) {
				return "No rook";
			}

			MoveAndReplaceTarget(ud, b, x, y, dx, dy);
			MoveAndReplaceTarget(ud, b, 7, 7, 5, 7);

			ArenaMessageFmt("%s (%s) Moves: Castle kingside",
			    GetPlayerName(ud, c), GetColorText(c));

			return NULL;
		} else if (dx == 2) {
			// castle queenside
			if (IsCoordAttackedBy(b, opp, 2, 7) ||
			    IsCoordAttackedBy(b, opp, 3, 7)) {
				return "Can't castle through or into check";
			}
			if (GetPieceAt(b, 1, 7)->type != TYPE_NONE ||
			    GetPieceAt(b, 2, 7)->type != TYPE_NONE ||
			    GetPieceAt(b, 3, 7)->type != TYPE_NONE) {
				return "Can't castle through pieces";
			}
			if (GetPieceAt(b, 0, 7)->type != TYPE_ROOK ||
			    GetPieceAt(b, 0, 7)->color != COLOR_BLACK) {
				return "No rook";
			}

			MoveAndReplaceTarget(ud, b, x, y, dx, dy);
			MoveAndReplaceTarget(ud, b, 0, 7, 3, 7);

			ArenaMessageFmt("%s (%s) Moves: Castle queenside",
			    GetPlayerName(ud, c), GetColorText(c));

			return NULL;
		}

	} else {
		return "Error castling";
	}

	return "Could not castle";
}
Пример #9
0
static
bool
PieceCanAttack(BOARD b, COLOR c, TYPE t, int x, int y, int dx, int dy)
{
	if (dx < 0 || dx >= 8) {
		return false;
	} else if (dy < 0 || dy >= 8) {
		return false;
	} else if (x == dx && y == dy) {
		// cant attack self
		return false;
	}

	int tx, ty; // temp x and y values
	PIECE *p;

	switch (t) {
	case TYPE_KING:
		for (int j = x - 1; j <= x + 1; ++j)
		for (int i = y - 1; i <= y + 1; ++i) {
			if (j == dx && i == dy) {
				return true;
			}
		}
		break;
	case TYPE_QUEEN:
		return PieceCanAttack(b, c, TYPE_BISHOP, x, y, dx, dy) ||
		    PieceCanAttack(b, c, TYPE_ROOK, x, y, dx, dy);
	case TYPE_ROOK:
		// search up
		for (int i = x + 1; i < 8; ++i) {
			if (i == dx && y == dy) {
				return true;
			}
			p = GetPieceAt(b, i, y);
			if (p->type != TYPE_NONE) {
				break;
			}
		}
		// search down
		for (int i = x - 1; i >= 0; --i) {
			if (i == dx && y == dy) {
				return true;
			}
			p = GetPieceAt(b, i, y);
			if (p->type != TYPE_NONE) {
				break;
			}
		}
		// search right
		for (int i = y + 1; i < 8; ++i) {
			if (i == dy && x == dx) {
				return true;
			}
			p = GetPieceAt(b, x, i);
			if (p->type != TYPE_NONE) {
				break;
			}
		}
		// search left
		for (int i = y - 1; i >= 0; --i) {
			if (i == dy && x == dx) {
				return true;
			}
			p = GetPieceAt(b, x, i);
			if (p->type != TYPE_NONE) {
				break;
			}
		}
		break;
	case TYPE_BISHOP:
		// search up-right
		for (int i = 1; x + i < 8 && y + i < 8; ++i) {
			if (x + i == dx && y + i == dy) {
				return true;
			}
			p = GetPieceAt(b, x + i, y + i);
			if (p->type != TYPE_NONE) {
				break;
			}
		}
		// search down-right
		for (int i = 1; x + i < 8 && y - i >= 0; ++i) {
			if (x + i == dx && y - i == dy) {
				return true;
			}
			p = GetPieceAt(b, x + i, y - i);
			if (p->type != TYPE_NONE) {
				break;
			}
		}
		// search up-left
		for (int i = 1; x - i >= 0 && y + i < 8; ++i) {
			if (x - i == dx && y + i == dy) {
				return true;
			}
			p = GetPieceAt(b, x - i, y + i);
			if (p->type != TYPE_NONE) {
				break;
			}
		}
		// search down-left
		for (int i = 1; x - i >= 0 && y - i >= 0; ++i) {
			if (x - i == dx && y - i == dy) {
				return true;
			}
			p = GetPieceAt(b, x - i, y - i);
			if (p->type != TYPE_NONE) {
				break;
			}
		}
		break;
	case TYPE_KNIGHT:
		tx = abs(dx - x);
		ty = abs(dy - y);
		if ((tx == 2 && ty == 1) ||
		    (tx == 1 && ty == 2)) {
			return true;
		}
		break;
	case TYPE_PAWN:
		// pawn special-case gheyness
		if (c == COLOR_WHITE) {
			if (y == 7) {
				return false;
			}
			if (x == dx) {
				// moving forward
				if (GetPieceAt(b, x, y + 1)->type == TYPE_NONE
				    && y + 1 == dy) {
					return true;
				}
				// initial 2 square move option
				if (y == 1 &&
				    GetPieceAt(b, x, y + 1)->type == TYPE_NONE &&
				    GetPieceAt(b, x, y + 2)->type == TYPE_NONE &&
				    y + 2 == dy) {
					return true;
				}
			}
			if (x > 0) {
				// check attack left
				if (GetPieceAt(b, x - 1, y + 1)->color == COLOR_BLACK &&
				    GetPieceAt(b, x - 1, y + 1)->type != TYPE_NONE) {
					if (dx == x - 1 && dy == y + 1) {
						return true;
					}

				}
			}

			if (x < 7) {
				// check attack right
				if (GetPieceAt(b, x + 1, y + 1)->color == COLOR_BLACK &&
				    GetPieceAt(b, x + 1, y + 1)->type != TYPE_NONE) {
					if (dx == x + 1 && dy == y + 1) {
						return true;
					}

				}
			}

		} else if (c == COLOR_BLACK) {
			if (y == 0) {
				return false;
			}
			if (x == dx) {
				// moving forward
				if (GetPieceAt(b, x, y - 1)->type == TYPE_NONE
				    && y - 1 == dy) {
					return true;
				}
				// initial 2 square move option
				if (y == 6 &&
				    GetPieceAt(b, x, y - 1)->type == TYPE_NONE &&
				    GetPieceAt(b, x, y - 2)->type == TYPE_NONE &&
				    y - 2 == dy) {
					return true;
				}
			}
			if (x > 0) {
				// check attack left
				if (GetPieceAt(b, x - 1, y - 1)->color == COLOR_WHITE &&
				    GetPieceAt(b, x - 1, y - 1)->type != TYPE_NONE) {
					if (dx == x - 1 && dy == y - 1) {
						return true;
					}

				}
			}
			if (x < 7) {
				// check attack right
				if (GetPieceAt(b, x + 1, y - 1)->color == COLOR_WHITE &&
				    GetPieceAt(b, x + 1, y - 1)->type != TYPE_NONE) {
					if (dx == x + 1 && dy == y - 1) {
						return true;
					}

				}
			}

		}
		break;
	}

	return false;
}
Пример #10
0
// TODO: Handle en passant
static
char*
TryMove(USER_DATA *ud, COLOR c, int x, int y, int dx, int dy)
{
	BOARD b = ud->board;

	PIECE *p = GetPieceAt(ud->board, x, y);
	if (p->type == TYPE_NONE) {
		return "No piece at that position!";
	} else if (p->color != c) {
		return "That piece is not yours!";
	}

	// check if this move is a castle attempt
	// TODO: check for rook movements
	if (p->type == TYPE_KING && IsCastleMove(c, x, y, dx, dy)) {
		if (ColorCanCastle(ud, c) == false) {
			return "You can no longer castle";
		}
		
		return TryCastle(ud, c, x, y, dx, dy);
	}

	// check that the piece can make this movement
	if (PieceCanAttack(ud->board, c, p->type, x, y, dx, dy) == false) {
		return "Piece can't make that movement";
	}

	// target piece
	PIECE *t = GetPieceAt(ud->board, dx, dy);
	if (t->type != TYPE_NONE && t->color == c) {
		return "You already have a piece in the destination position!";
	}

	// make the movements to check for check, but store the data
	// in case the board needs to be reverted
	PIECE old_p = *p;
	PIECE old_t = *t;
	SetPieceAt(b, dx, dy, p->color, p->type);
	SetPieceAt(b, x, y, COLOR_NONE, TYPE_NONE);

	// find the king and test for check
	int kingx, kingy;
	FindKing(b, c, &kingx, &kingy);
	if (IsCoordAttackedBy(b, GetOppositeColor(c), kingx, kingy) == true) {
		// restore saved positions
		SetPieceAt(b, x, y, old_p.color, old_p.type);
		SetPieceAt(b, dx, dy, old_t.color, old_t.type);
		return "That move would place your King in check!";
	}

	//
	// At this point, the move was successful
	//

	// make the pieces blink
	// TODO: this will erroneously leave pieces on if 2 moves
	// are made quickly
	uint32_t objid = LvzGetObjId(old_p.color, old_p.type, dx, dy);
	SetTimer(500, (void*)objid, (void*)0);
	SetTimer(1000, (void*)objid, (void*)1);
	SetTimer(1500, (void*)objid, (void*)0);
	SetTimer(2000, (void*)objid, (void*)1);
	SetTimer(2500, (void*)objid, (void*)0);
	SetTimer(3000, (void*)objid, (void*)1);
	if (old_t.type != TYPE_NONE) {
		// flash the captured piece
		objid = LvzGetObjId(old_t.color, old_t.type, dx, dy);
		SetTimer(500, (void*)objid, (void*)1);
		SetTimer(1000, (void*)objid, (void*)0);
		SetTimer(1500, (void*)objid, (void*)1);
		SetTimer(2000, (void*)objid, (void*)0);
		SetTimer(2500, (void*)objid, (void*)1);
		SetTimer(3000, (void*)objid, (void*)0);
	}

	if (old_p.type == TYPE_KING) {
		// kings cant castle once theyve moved
		if (old_p.color == COLOR_WHITE) {
			ud->white_can_castle = false;
		} else if (old_p.color == COLOR_BLACK) {
			ud->black_can_castle = false;
		}
	}

	// set if a piece has been captured
	bool capture = old_t.type != TYPE_NONE;

	// remove drawing of the old pieces
	LvzActivate(ud, NULL, old_p.color, old_p.type, x, y, false);
	if (capture) {
		LvzActivate(ud, NULL, old_t.color, old_t.type, dx, dy, false);
	}

	// check for pawn promotions
	// TODO: handle underpromotions
	bool promoted = false;
	p = GetPieceAt(b, dx, dy);
	if (p->type == TYPE_PAWN) {
		if (p->color == COLOR_WHITE && dy == 7) {
			p->type = TYPE_QUEEN;
			promoted = true;
		} else if (p->color == COLOR_BLACK && dy == 0) {
			p->type = TYPE_QUEEN;
			promoted = true;
		}
	}

	// draw the new piece
	LvzActivate(ud, NULL, old_p.color, old_p.type, dx, dy, true);
	objid = LvzGetObjId(old_p.color, old_p.type, dx, dy);

	// create move notation
	char move[6];
	move[0] = x + 'a';
	move[1] = y + '1';
	move[2] = ',';
	move[3] = dx + 'a';
	move[4] = dy + '1';
	move[5] = '\0';

	// announce the move
	char line[256];
	snprintf(line, 256, "%s (%s) Moves: %s",
	    GetPlayerName(ud, c), GetColorText(ud->to_move), move);
	if (capture) {
		// add capture line
		char capture[64];
		snprintf(capture, 64, ", capturing a %s!", GetTypeName(old_t.type));
		strlcat(line, capture, 256);
	}
	if (promoted == true) {
		// add promition line
		strlcat(line, " Pawn promoted to Queen!", 256);
	}
	FindKing(b, GetOppositeColor(c), &kingx, &kingy);
	if (IsCoordAttackedBy(b, c, kingx, kingy) == true) {
		if (IsCheckmatedBy(b, c, kingx, kingy) == true) {
			strlcat(line, " Checkmate!", 256);
			ArenaMessage(line);

			char gametime[32];
			TicksToText(gametime, 32, GetTicksMs() - ud->start_tick);
			StopGame(ud, "%s Wins in %s!", GetPlayerName(ud, c), gametime);
		} else {
			strlcat(line, " Check!", 256);
			ArenaMessage(line);
		}
	} else {
		ArenaMessage(line);
	}

	return NULL;
}