Starlight-30036225 / ChessTCP

FILLMELATER
0 stars 0 forks source link

Castling #22

Closed Starlight-30036225 closed 9 months ago

Starlight-30036225 commented 9 months ago

Castling is going to take a lot of work, as there are a lot of things to check to see if it is possible.

The rules of castling are: -Neither king nor rook can have moved -The king moves two spaces towards the rook -The rook moves to the opposite side of the king -The king cannot move past a space that is in check -The king cannot be in check -There must be no spaces between rook and king

Getting the spacing right for this is going to be tricky

Starlight-30036225 commented 9 months ago

For this development I have created a new base board state: image

Fen: (2qk4/8/8/8/8/8/8/R3K2R)

By the rules listed above the king should not be able to castle left as long as the queen is in place but should be able to castle to the right.

Starlight-30036225 commented 9 months ago

Neither king nor rook can have moved:

Like I have done with pawns, I will create a new boolean to check if either piece has moved yet.

To be able to set this to false after a move I need to override the move function in both. This is a miniscule change for now:

@Override public boolean move(Piece[][] board, String NewLocation) { if (super.move(board, NewLocation)) { FirstMove = false; return true; } return false; }

Starlight-30036225 commented 9 months ago

As this is quite complex, I will move it into its own function.

I will leave the responsibility to request a castling to the king, as it would look no different inside a rook.

` private boolean Castle(Piece[][] board, List moves) { boolean added = false; if (x + 3 < 8 && //checks in any passed space is in check isLocationSafe(board, this, x, y) && isLocationSafe(board, this, x + 1, y) && board[x + 1][y] == null && isLocationSafe(board, this, x + 2, y) && board[x + 2][y] == null) {

        int counter = 3;    //Starts the counter at 3, as the rook must be atleast that far away
        boolean valid = false;

        while (counter + x < 8) {  
            if (board[x + counter][y] != null) {    //if there is a piece here, if its not a rook this check fails
                valid = (board[x + counter][y].white == white && //Is piece same colour
                        board[x + counter][y].getClass() == Rook.class);  //is Piece a rook
                break;
            }
            counter++;
        }
        if (valid) {
            moves.add((x + 2) + "" + y);    //adds the move to the list
            added = true;
        }
    }

    if (x - 3 < 8 &&   //checks in any passed space is in check
            isLocationSafe(board, this, x, y) &&
            isLocationSafe(board, this, x - 1, y) && board[x - 1][y] == null &&
            isLocationSafe(board, this, x - 2, y) && board[x - 2][y] == null) {

        int counter = 3;    //Starts the counter at 3, as the rook must be atleast that far away
        boolean valid = false;

        while (counter - x > -1) {   //Keeps the checks inside range
            if (board[x - counter][y] != null) {
                valid = (board[x - counter][y].white == white && //Is piece same colour
                        board[x - counter][y].getClass() == Rook.class);  //is Piece a rook
                break;
            }
            counter++;
        }
        if (valid) {
            moves.add((x - 2) + "" + y);
            added = true;
        }
    }
    return added;
}`

I know its bad to have this much repeated code but shhh

This should check both sides for a rook, if it finds one and all spaces are safe it will add the move to the list

Starlight-30036225 commented 9 months ago

I forgot to check that both the king and the rook have not moved

Lets do that quick.

((Rook)board[x + counter][y]).FirstMove);

and if (!FirstMove) {return false;} //Can only do this on first move

should do fine

Starlight-30036225 commented 9 months ago

Now lets see if it detects these as possible:

image Perfect

Now lets tell the king when its castling so it knows to update the rook.

Starlight-30036225 commented 9 months ago

` int StartX = this.x; //Saves X to check later int newX = Character.getNumericValue(NewLocation.charAt(0)); boolean AttemptingCastle = (abs(StartX - newX) == 2); //If this piece is moving 2 spaces, its castling

    if (!super.move(board, NewLocation)) {return false;} ///Gatekeeping
    FirstMove = false;
    if (!AttemptingCastle) { return true; }`

Inside the move function, I am checking the distance between the starting and end location of the kings move. If it is 2 spaces, it must be a castle.

If its not trying to castle, it can leave the function here and ignore whats coming next

`int RookDirection = ((StartX - newX) > 0) ? -1 : 1; //Finds which side the rook is on

    //You know there is going to be a rook or this move wouldnt have been possible
    while (board[x + RookDirection][y] == null) {  //scans that direction for the rook
        RookDirection += RookDirection;
    }`

This finds the rook

Rook rook = (Rook) board[x + RookDirection][y]; //Get the rook rook.move(board, this.x - (((StartX - newX) > 0) ? -1 : 1) + "" + y);

Then this should tell the rook to move to the other side of the king

Starlight-30036225 commented 9 months ago

Lets test

image

image

Thats not right...

The rook doesnt want to move

Starlight-30036225 commented 9 months ago

I've found the problem. Because at this point, the king has already moved the rook thinks its illegal to get to the other side of the king. So im going to need to force the move. Thats fine.

board[rook.x][y] = null; rook.x = this.x - (((StartX - newX) > 0) ? -1 : 1); //Place the rook on the other side of the king board[rook.x][y] = rook;

This should do it

Starlight-30036225 commented 9 months ago

image

Much better

Now lets get rid of the queen and test the other one

Starlight-30036225 commented 9 months ago

image Crap baskets

Starlight-30036225 commented 9 months ago

image

Better

while (x- counter > -1) { //Keeps the checks inside range

this subtraction was the wrong way round. Fixed now