Found this challenge on CodeFights and would love a review of my style.
Description
An amazon (also known as a queen+knight compound) is an imaginary chess piece that can move like a queen or a knight (or, equivalently, like a rook, bishop, or knight). The diagram below shows all squares which the amazon attacks from e4 (circles represent knight-like moves while crosses correspond to queen-like moves).
Recently you've come across a diagram with only three pieces left on the board: a white amazon, white king and black king. It's black's move. You don't have time to determine whether the game is over or not, but you'd like to figure it out in your head. Unfortunately, the diagram is smudged and you can't see the position of the black's king, so it looks like you'll have to check them all.
Given the positions of white pieces on a standard chessboard, determine the number of possible black king's positions such that:
- it's checkmate (i.e. black's king is under amazon's attack and it cannot make a valid move);
- it's check (i.e. black's king is under amazon's attack but it can reach a safe square in one move);
- it's stalemate (i.e. black's king is on a safe square but it cannot make a valid move);
- black's king is on a safe square and it can make a valid move.
Note that two kings cannot be placed on two adjacent squares (including two diagonally adjacent ones).
Example
For
king = "d3"
andamazon = "e4
", the output should beamazonCheckmate(king, amazon) = [5, 21, 0, 29]
.
Code
def amazonCheckmate(king, amazon):
# is in range of n for a and b
def squared_range(a, b, n):
return (a[0] >= b[0] -n and a[0] <= b[0] + n and a[1] >= b[1]-n and a[1] <= b[1] + n)
# if any square +1 // -1 for y and x are not under check ==> King escapes
def no_valid_moves(a, b):
if(a!=1):
if([a-1,b] in notUnderCheck):
return False
if(b!=1):
if([a-1,b-1] in notUnderCheck):
return False
if(b!=8):
if([a-1,b+1] in notUnderCheck):
return False
if(a!=8):
if([a+1,b] in notUnderCheck):
return False
if(b!=1):
if([a+1,b-1] in notUnderCheck):
return False
if(b!=8):
if([a+1,b+1] in notUnderCheck):
return False
if(b!=8):
if([a,b+1] in notUnderCheck):
return False
if(b!=1):
if([a,b-1] in notUnderCheck):
return False
return True
# declaring variables
result = [0, 0, 0, 0]
letters = ['','a','b','c','d','e','f','g','h']
notUnderCheck = []
underCheck = []
k_file = letters.index(king[0])
k_col = int(king[1])
a_file = letters.index(amazon[0])
a_col = int(amazon[1])
k = [k_file, k_col]
q = [a_file, a_col]
# if king defends queen the square where queens stand is undercheck else not under check
if(squared_range(k, q, 1)):
underCheck.append(q)
else:
notUnderCheck.append(q)
# a grid 8x8 check which squares are under check and which are not
for x in range(1, 9):
for y in range(1, 9):
# Squares to excldue are defended by King or postion of Amazon
if(not squared_range([x,y], k, 1) and not [x,y] == q):
# if in deadly square of queen 5x5
#
if(squared_range([x,y],q, 2)):
underCheck.append([x,y])
# Check if on the same file and not if king is in between
elif (x == a_file):
if(not (k_file == a_file and (y > k_col > a_col or y < k_col < a_col))):
underCheck.append([x,y])
# Check if on the same column and not if king in between
elif( y == a_col):
if(not (k_col == a_col and ( x > k_file > a_file or x < k_file < a_file))):
underCheck.append([x,y])
# Check diagonal and not if king in between
# Black_King on Diagonaal van Queen
elif(abs(x - a_file) == abs(y - a_col)):
if( not(abs(k_file - a_file) == abs(k_col - a_col)
and ( ( x < k_file < a_file and y < k_col < a_col)
or (x < k_file < a_file and y > k_col > a_col)
or (x > k_file > a_file and y < k_col < a_col)
or (x > k_file > a_file and y < k_col < a_col) ) ) ):
underCheck.append([x,y])
else:
notUnderCheck.append([x, y])
# Add the squares where to White_King stands to checksquares
elif(squared_range([x,y], k, 1)):
underCheck.append([x,y])
# for each cell in grid check surounding cells strengths update result accordingly
for x in range(1, 9):
for y in range(1, 9):
# Exclude q and kings range
if(not squared_range([x,y], k, 1) and not [x,y] == q):
# if current square under Check
if([x, y] in underCheck):
# if no possible moves result[0]++
# else result[1]++
if(no_valid_moves(x, y)):
print("Checkmate at: [" + str(x) + ", " + str(y) + "]")
result[0] += 1
else:
print("Check at: [" + str(x) + ", " + str(y) + "]")
result[1] += 1
else:
# if no possible moves result[2]++
# else result[3]++
if(no_valid_moves(x, y)):
print("Stuck at: [" + str(x) + ", " + str(y) + "]")
result[2] += 1
else:
print("Safe at: [" + str(x) + ", " + str(y) + "]")
result[3] += 1
return result
Question
no_valid_moves
looks clunky as hell! How can this be made beautifull again?- Is my general logic ok, or should I have divided the problem in easier to comprehend functions?
- Any stylistic review is welcome too.