Пример #1
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;
}
Пример #2
0
//get color of CPU - opposite of user's color.
color_t Settings_CPUColor_Get()
{

	color_t user_color = Settings_UserColor_Get();

	return GetOppositeColor(user_color);

}
Пример #3
0
void
CmdMove(CORE_DATA *cd)
{
	USER_DATA *ud = UD(cd);

	// the game hasnt started
	if (ud->in_progress == false) {
		Reply("The game has not yet begun");
		return;
	}

	// check for correct arg count
	if (cd->cmd_argc != 2) {
		ReplyFmt("Usage: !move Coord,Coord");
		ReplyFmt("Example: !move e2,e4");
		return;
	}

	// make sure the player is playing
	if (IsPlaying(ud, cd->cmd_name) == false) {
		Reply("You are not playing in this match");
		return;
	}

	// replies to players in-game are via arena

	// check whos turn it is
	if (GetColor(ud, cd->cmd_name) != ud->to_move) {
		ArenaMessage("It is not your move");
		return;
	}
				
	// parse argument
	char xstr[3];
	char ystr[3];
	DelimArgs(xstr, 3, cd->cmd_argv[1], 0, ',', false);
	DelimArgs(ystr, 3, cd->cmd_argv[1], 1, ',', false);

	int x1, y1, x2, y2;
	if (ParseCoords(xstr, &x1, &y1) == true &&
	    ParseCoords(ystr, &x2, &y2) == true) {
		
		char *err = TryMove(ud, ud->to_move, x1, y1, x2, y2);
		if (err == NULL && ud->in_progress == true) {
			// successful moves are announced in TryMove()
			ud->to_move = GetOppositeColor(ud->to_move);
			LvzToMove(ud->to_move, NULL);
			ArenaMessageFmt("%s (%s) to Move",
			    GetPlayerName(ud, ud->to_move), GetColorText(ud->to_move));
		} else if (ud->in_progress == true) {
			ArenaMessageFmt("Couldn't move: %s", err);
		}
	} else {
		ArenaMessageFmt("Invalid coordinates");
	}
}
Пример #4
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";
}
Пример #5
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;
}