Reputation: 25
I am trying to write a program that will return True if the white king on a chess board is in check. The pieces on the board are generated as a string and formatted as such, where the lowercase values are white and the uppercase are black.:
r*x***k****p***P*****Q*****kp****K*****p***Pb****p***PP***X***KR
| | |X| | | |K|R|
| |p| | | |P|P| |
| | | |P|b| | | |
| |K| | | | | |p|
| | | |k|p| | | |
| | | | | |Q| | |
| | | |p| | | |P|
|r| |x| | | |k| |
I understand how to transform the units on the board into x and y coordinates, and the mathematical operations of the pieces on the board (check pawns on +7 and +9, check rooks on ...-2, -1, +1,+2... and ...-16, -8, +8, +16..., but i can't translate this to python, or stop the check if it hits another piece or before it goes "past" the board and loops around again. Here is my code so far, but nothing really working correctly:
def white_check(coded_position):
w_king = coded_position.find("x")
w_king_x = w_king%8
w_king_y = w_king//8
result = False
print(w_king)
# This doesn't work if king is on x = 0 or 8
# Returns true if pawn checks
# if coded_position[w_king+7] == "P" or coded_position[w_king+9] == "P":
#result = True
# try using for loops and going up 1 / 8 at a time and trying each case for rooks / and bishops
# checks right side for rooks
for i in range(w_king,w_king-w_king_x+8):
if coded_position[i] != "*" and coded_position[i] != "K":
result = False
break
if coded_position[i] == "K":
result = True
# checks left side for rooks
for i in range(w_king,w_king-w_king_x,-1):
if coded_position[i] != "*" and coded_position[i] != "K":
result = False
break
if coded_position[i] == "K":
result = True
print(result)
return result
I think I am really over-complicating this, is there anything obvious that I am missing?
Upvotes: 2
Views: 1816
Reputation: 166
I think you are making this more complicated than it is. Here are the steps I would use:
Find the king positions.
Loop through all 8 directions from that location in a nested loop.
When you reach a white piece (uppercase letter), break that direction.
When you reach end of board, break that direction.
If you reach a black piece (lowercase) you have 4 options to check:
a. Piece is orthogonally from king and is a rook
b. Piece is diagonally from king and is a bishop
c. Piece is 1 square away diagonally from king and is a pawn
d. Any direction and piece is a queen
If any of a-d is True, then return True (king is in check). If the entire loop ends, return False.
If you need I can give you the code for my checker.
Upvotes: 1
Reputation: 3575
I'm not going to give you code (right now at least), but I can give some steps.
Currently looks like you are storing everything as an index on the long input line. This makes it harder, so step one is to represent the board as a list of strings, where is one is 8 long.
The result you want is
board = ["r*x***k*",
"***p***P",
"*****Q**",
"***kp***",
"*K*****p",
"***Pb***",
"*p***PP*",
"**X***KR"]
So now the white king is at board[0][2]
, and black is moving up the board. Let's call this (0, 2).
Now you need to work out if (0, 2) is in check. The way I would do this is work out for each type of piece, where one could be, to put this position in check. You could store this as a list of differences from the current king location, and for each of those you check if the thing that's in them is the piece that can cause check.
movements = {
"P": [(1,-1), (1,1)],
"R": [*[(0, i), (0, -i), (i, 0), (-i, 0)] for i in range(7)],
}
Here are movements for a pawn and rook. If there is a pawn on (0, 2)+(1, 1) or (0, 2)+(1,-1), and those positions are inside the grid, the pawn is checking (0, 2).
To be inside the grid, both numbers have to be between 0 and 7 inclusive.
For the rook it's a bit more complicated. Positions a rook can attack from are when either the row is the same or the column is the same, that's why there's always a 0 in one of the movements above. With the rook you have the added complexity, that you have to discount anything that's in the way. It might be easier to search everything left of the king, right of, above, and below, and stop searching that when
I think that's enough to complete this. Remember, you don't have to check every single location, you just need to find one piece that's threatening the king.
Afterwards it's fairly simple to work out if a king is in checkmate, because it's just if a king is in check, and all the places around it are also in check, or invalid places.
Upvotes: 1