Search code examples
pythonclasschess

Chess final: king and rook vs king in python


I've got some issues with this simple chess code in python. It is part of a weekly assignment; this is what I got so far:

from math import sqrt
from random import randint,shuffle,seed
def rand_pos():
    return [randint(0,7),randint(0,7)]

#first, classes defining the kings and the rook; 
#their only attribute is a randomly generated position on the chessboard. 
#Each of them has its special print method that will be used in the Chessboard (Scacchiera) class.
class W_king:
    def __init__(self,coord=rand_pos()):
        self.coord=coord
        self.x=coord[1]
        self.y=coord[0]
    def __repr__(self):
        return "R"
class B_king:
    def __init__(self,coord=rand_pos()):
        self.coord=coord
        self.x=coord[1]
        self.y=coord[0]
    def __repr__(self):
        return "r"
class Rook:
    def __init__(self,coord=rand_pos()):
        self.coord=coord
        self.x=coord[1]
        self.y=coord[0]
    def __repr__(self):
        return "T"

#the following will be used to calculate the distance between the kings and between a king and the rook; 
#I'll use it in the while statements later in the Scacchiera class to check if the kings are generated too near or stuff
def distance(n1,n2):
    return sqrt(sum((n1.coord[i]-n2.coord[i])**2 for i in [0,1]))

class Scacchiera:
    def __init__(self,w_king=W_king(),b_king=B_king(),rook=Rook(),boxes=[[" " for y in range(8)] for x in range(8)]):
        self.w_king=w_king
        self.b_king=b_king
        self.rook=rook
        self.boxes=boxes
        #here it is: while the two kings are generated too near, 
        #get the black king new coordinates
        while distance(self.b_king,self.w_king)<2:
            self.b_king.coord=[randint(0,7),randint(0,7)]
        #...and, while the white king (or the black king) and the rook have the same coordinates 
        #or the black king is in the rook's sight, 
        #get a new pair of coordinates for the rook:
        while self.w_king.coord==self.rook.coord or self.b_king.coord==self.rook.coord or self.rook.x==self.b_king.x or self.rook.y==self.b_king.y:
            self.rook.coord=[randint(0,7),randint(0,7)]
        print distance(self.b_king,self.w_king) #to check, just for me
        #the function conv switches to the chessboard's coordinates e.g. e4, h5, etc
        print conv(self.w_king.coord),conv(self.b_king.coord),conv(self.rook.coord)
    def __repr__(self):
        #self.boxes is an array of blank spaces " ",
        #and in the right place the kings and the rook are placed
        scacchiera=self.boxes[:]
        scacchiera[self.w_king.x][self.w_king.y]=self.w_king
        scacchiera[self.b_king.x][self.b_king.y]=self.b_king
        scacchiera[self.rook.x][self.rook.y]=self.rook
        return "\n".join([str(8-i)+" "+" ".join(str(scacchiera[i][j]) for j in range(8)) for i in range(8)])+"\n  "+" ".join([chr(97+k) for k in range(8)])
    def check(self,king):
        #no need for this for now
        return self.rook.x==king.x or self.rook.y==king.y
    def black_legal_moves(self,mossa):
        future_king=B_king([self.b_king.y+mossa[0],self.b_king.x+mossa[1]])
        if distance(self.w_king,future_king)<2 or self.check(future_king):
            return False
        else:
            return True

    def new_mossa_random(self):
        #this method chooses randomly a new position for the black king from the list of adjacent cells 
        #and tests if it's legal with the method above. If it's not, it deletes it from the list and re-tries 
        moves_list=[[self.b_king.y+hor,self.b_king.x+ver] for ver in [-1,0,1] for hor in [-1,0,1] if not hor==ver==0]
        shuffle(moves_list)
        move=moves_list[0]
        #while it's not legal or the coordinates are out of the board:
        while not self.black_legal_moves(move) or not 0<=move[0]<=7 or not 0<=move[1]<=7:
            del moves_list[0]
            if not moves_list:
                return None
            move=moves_list[0]
        return move
def conv(coord):
    return [chr(coord[0]+97),8-coord[1]]

#you just need to run it:
seed()
scacchiera=Scacchiera()
print scacchiera
print conv(scacchiera.new_mossa_random())

The issues are two:

  • My code, though incomplete, seems correct to me in the chessboard generation section. Nonetheless, often (nearly three times out of ten) the kings are next to each other or the rook and a king are placed one over the other, or the random move for the black king isn't even near of his box.
  • Very often, the code keeps running and won't print any chessboard; it seems like it sticks on the two whiles at the beginning of Scacchiera.

NB: F5-ing the script on your PC will print, in the following order:

  1. The distance between the two kings,

  2. The coordinates on the chessboard of: the white king, the black king, and then the rook

  3. The chessboard with the pieces on the board

  4. The coordinates of a new random move for the black king.

Let me know if I should add some other info.


Solution

  • In case of collision, you're changing the coord member on the pieces. But the positions are also stored in x and y, which are not updated.

    I'd suggest that you keep only x and y or only coord in your classes. if you want to get fancy, you could keep coord and make x and y into properties by using @property.