Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import numpy as np
- import tkinter as tk
- import os.path
- import os
- # CHECK, PROMOTION AND CASTLING
- tile_width = 60
- board_width = 8 * tile_width
- board_height = board_width
- pic_dir = "./Pictures" # These line has been modified to give the relative path
- DICT = {"black_tile":"black.gif",
- "Bb":"blackbishop.gif",
- "Bw":"whitebishop.gif",
- "Kb":"blackking.gif",
- "Kw":"whiteking.gif",
- "Nb":"blackknight.gif",
- "Nw":"whiteknight.gif",
- "Pb":"blackpawn.gif",
- "Pw":"whitepawn.gif",
- "Qb":"blackqueen.gif",
- "Qw":"whitequeen.gif",
- "Rb":"blackrook.gif",
- "Rw":"whiterook.gif",
- "white_tile":"white.gif"
- }
- class ChessException(Exception):
- """ Base class for chess exceptions"""
- pass
- class InvalidTurnException(ChessException):
- def __init__(self, value):
- self.parameter = value
- def __str__(self):
- return repr(self.parameter)
- class InvalidMoveException(ChessException):
- def __init__(self, value):
- self.parameter = value
- def __str__(self):
- return repr(self.parameter)
- class OccupiedFriendlySquareException(InvalidMoveException):
- def __init__(self, value):
- self.parameter = value
- def __str__(self):
- return repr(self.parameter)
- class KingThreatenedSquareException(InvalidMoveException):
- def __init__(self, value):
- self.parameter = value
- def __str__(self):
- return repr(self.parameter)
- class ObscurePathException(InvalidMoveException):
- def __init__(self, value):
- self.parameter = value
- def __str__(self):
- return repr(self.parameter)
- class ChessBoard:
- count = 0 # This is the counter to keep track of moves
- def __init__(self):
- self.objectboard = self.form_board()
- self.symbolboard = self.draw_board(self.objectboard.T)
- # Initialize the GUI
- self.window = tk.Tk()
- self.canvas = tk.Canvas(width = board_width, height = board_height)
- self.canvas.pack()
- self.images = {}
- for image_file_name in DICT:
- f = os.path.join(pic_dir, DICT[image_file_name])
- if not os.path.exists(f):
- print("Error: Cannot find image file: %s at %s - aborting"%(DICT[image_file_name], f))
- exit(-1)
- self.images[image_file_name]= tk.PhotoImage(file=f)
- def __str__(self):
- string = ''
- # Transpose is necessary to make the board as we are accustomed to
- for i in reversed(range(8)): # It is reversed so that white is at the bottom
- string += str(self.symbolboard[i]) + '\n'
- return string
- def show_board(self, symbolboard):
- for j in range(8):
- y = j * tile_width
- for i in range(8):
- x = i * tile_width
- if (i % 2 == ((1 + j) % 2)):
- tile = self.images['black_tile']
- else:
- tile = self.images['white_tile']
- self.canvas.create_image(x, y, anchor = tk.NW, image=tile)
- for j in (range(8)):
- for i in (range(8)):
- piece = symbolboard[i][j]
- if piece == '0 ':
- continue # There is no piece on this tile
- tile = self.images[piece]
- x = j * tile_width
- y = (7 - i) * tile_width
- self.canvas.create_image(x, y, anchor=tk.NW, image = tile)
- def form_board(self): # Forms the board and puts the pieces on the respective positions
- board = np.zeros((8,8), dtype = object)
- # Now we should put the pieces on the board
- WhiteRook1 = Rook(0, 0, 'w', board)
- WhiteRook2 = Rook(7, 0, 'w', board)
- WhiteKnight1 = Knight(1, 0, 'w', board)
- WhiteKnight2 = Knight(6, 0, 'w', board)
- WhiteBishop1 = Bishop(2, 0, 'w', board)
- WhiteBishop2 = Bishop(5, 0, 'w', board)
- WhiteQueen = Queen(3, 0, 'w', board)
- WhiteKing = King(4, 0, 'w', board)
- # Now we should put the pawns
- for i in range(8):
- exec("WPawn" + str(i+1) + "= Pawn(i, 1, 'w', board)")
- # This syntax is for changing variable names
- # Now put the black pieces
- BlackRook1 = Rook(0, 7, 'b', board)
- BlackRook2 = Rook(7, 7, 'b', board)
- BlackKnight1 = Knight(1, 7, 'b', board)
- BlackKnight2 = Knight(6, 7, 'b', board)
- BlackBishop1 = Bishop(2, 7, 'b', board)
- BlackBishop2 = Bishop(5, 7, 'b', board)
- BlackQueen = Queen(3, 7, 'b', board)
- BlackKing = King(4, 7, 'b', board)
- # Now we should put the pawns
- for i in range(8):
- exec("BPawn" + str(i+1) + "= Pawn(i, 6, 'b', board)")
- return board
- def draw_board(self, board):
- func_sym_col = np.vectorize(self.retrieve_piece)
- symbolic_board = func_sym_col(board)
- return symbolic_board
- @staticmethod # This method does not need to access class data
- def retrieve_piece(piece):
- if isinstance(piece, ChessPiece):
- return str(piece.symbol+piece.color)
- else:
- return '0 '
- def rules(self, piece, i, j, m, n):
- board = self.objectboard
- #symboard = self.draw_board(board)
- if ((self.__class__.count % 2) == 0):
- if (piece.color == 'b'):
- raise InvalidTurnException('It is Whites turn to play')
- else:
- if (piece.color == 'w'):
- raise InvalidTurnException('It is Blacks turn to play')
- piece_type = piece.symbol # Rules depend on the piece
- # Implement check
- check_new_pos = 0 # We should modify this write a loop over other pieces
- opponent_king = 0
- auxboard = []
- check1 = ((m - i) >= 0)
- check2 = ((n - j) >= 0)
- if piece_type == 'K':
- if (abs(i - m) > 1):
- raise InvalidMoveException('This is not a valid move for the King')
- elif (abs(j - n) > 1) :
- raise InvalidMoveException('This is not a valid move for the King')
- elif check_new_pos:
- raise KingThreatenedSquareException('The King cannot move to a threatened square!!!')
- elif opponent_king:
- raise KingThreatenedSquareException('You cannot go too close to the opponent king')
- # Castling implementation
- elif piece_type == 'Q':
- if not ((abs((i - m) / (j - n)) == 1) or ((i - m) == 0) or ((j - n) == 0)):
- raise InvalidMoveException('The queen cannot move like this')
- if (i - m) == 0:
- if check2:
- auxboard = board[i][j+1:n]
- else:
- auxboard = board[i][n+1:j]
- elif (j - n) == 0:
- if check1:
- auxboard = board[i+1:m][j]
- else:
- auxboard = board[m+1:i][j]
- else:
- if check1 and check2:
- for ct in range(m - i - 1):
- auxboard.append(board[i + 1 + ct][j + 1 + ct])
- elif check1 and (not check2):
- for ct in range(m - i - 1):
- auxboard.append(board[i + 1 + ct][j - 1 - ct])
- elif (not check1) and check2:
- for ct in range(i - m - 1):
- auxboard.append(board[i - 1 - ct][j + 1 + ct])
- elif (not check1) and (not check2):
- for ct in range(i - m - 1):
- auxboard.append(board[i - 1 - ct][j - 1 - ct])
- if not (all(p == 0 for p in auxboard)):
- raise ObscurePathException('The path is obscured')
- elif piece_type == 'R':
- if not (((i - m) == 0) or ((j - n) == 0)):
- raise InvalidMoveException('The rook cannot move like this')
- if (i - m) == 0:
- if check2:
- auxboard = board[i][j+1:n]
- else:
- auxboard = board[i][n+1:j]
- elif (j - n) == 0:
- if check1:
- auxboard = board[i+1:m][j]
- else:
- auxboard = board[m+1:i][j]
- if not (all(p == 0 for p in auxboard)):
- raise ObscurePathException('The path is obscured')
- elif piece_type == 'B':
- if not (abs((i - m) / (j - n)) == 1):
- raise InvalidMoveException('The bishop cannot move like this')
- if check1 and check2:
- for ct in range(m - i - 1):
- auxboard.append(board[i + 1 + ct][j + 1 + ct])
- elif check1 and (not check2):
- for ct in range(m - i - 1):
- auxboard.append(board[i + 1 + ct][j - 1 - ct])
- elif (not check1) and check2:
- for ct in range(i - m - 1):
- auxboard.append(board[i - 1 - ct][j + 1 + ct])
- elif (not check1) and (not check2):
- for ct in range(i - m - 1):
- auxboard.append(board[i - 1 - ct][j - 1 - ct])
- if not (all(p == 0 for p in auxboard)):
- raise ObscurePathException('The path is obscured')
- elif piece_type == 'N': # The path may be obscured this time
- if not (((abs(i - m) == 2) and (abs(j - n) == 1)) or ((abs(i - m) == 1) and (abs(j - n) == 2))):
- raise InvalidMoveException('The knight cannot move like this')
- elif piece_type == 'P':
- if piece.color == 'w':
- if piece.has_already_moved == 0:
- if not(((n - j) == 2) or ((n - j) == 1) and ((i - m) == 0) ):
- raise InvalidMoveException('The pawn cannot move like this')
- elif (board[m][n] != 0) or (board[m][n - 1] != 0 if (n - j) == 2 else False):
- if ((abs(i - m) == 1) and (n - j == 1)):
- pass
- else:
- raise InvalidMoveException('The pawn cannot attack forward')
- else: # Pawn has moved
- if not((n - j) == 1):
- raise InvalidMoveException('The pawn cannot move like this')
- elif (board[m][n] != 0):
- if ((abs(i - m) == 1) and (n - j == 1)):
- pass
- else:
- raise InvalidMoveException('The pawn cannot attack forward')
- else: # Black pawn
- if piece.has_already_moved == 0:
- if not(((n - j) == -2) or ((n - j) == -1) and ((i - m) == 0)):
- raise InvalidMoveException('The pawn cannot move like this')
- elif (board[m][n] != 0) or (board[m][n - 1] != 0 if (n - j) == 2 else False):
- if ((abs(i - m) == 1) and (n - j == -1)):
- pass
- else:
- raise InvalidMoveException('The pawn cannot attack forward')
- elif (board[m][n] != 0) or (board[m][n + 1] != 0 if (n - j) == -2 else False):
- raise InvalidMoveException('The pawn cannot attack forward')
- else: # Pawn has moved
- if not((n - j) == -1):
- raise InvalidMoveException('The pawn cannot move like this')
- elif (board[m][n] != 0):
- if ((abs(i - m) == 1) and (n - j == -1)):
- pass
- else:
- raise InvalidMoveException('The pawn cannot attack forward')
- # Implement one cannot move to a square containing same color piece
- if board[m][n] != 0: # There is a piece in the final position
- if board[i][j].color == board[m][n].color:# Two pieces are of the same color
- raise OccupiedFriendlySquareException("You cannot go to your own pieces location")
- elif board[m][n].symbol == 'K':# The opponent king is in the location
- raise InvalidMoveException("You cannot eat the KING")
- if ((piece_type == 'P') or (piece_type == 'K')):
- piece.has_already_moved = True
- return True
- def move(self, position):
- # These two strings are for board coordinates
- letstr = 'abcdefgh'
- numstr = '12345678'
- board = self.objectboard
- if not (len(position) == 4):
- raise ValueError('The position string should consist of 4 characters');
- # Get the final and initial positions
- initial_pos = position[:2]
- final_pos = position[-2:]
- # First perform the checks
- if not (str == type(initial_pos) and (str == type(final_pos))): # Check if the arguments are strings
- raise TypeError('The supplied positions should be strings!')
- elif not ((initial_pos[0] in letstr) and (initial_pos[1] in numstr)): # Check if they fulfill the condition to be on the board
- raise InvalidMoveException('The initial position values should be between a1 and h8')
- elif not ((final_pos[0] in letstr) and (final_pos[1] in numstr)): # Check if they fulfill the condition to be on the board
- raise InvalidMoveException('The final position values should be between a1 and h8')
- elif initial_pos == final_pos:
- raise InvalidMoveException('Final position should be different from the initial position')
- # Now determine if there is a piece on the initial square
- i = letstr.index(initial_pos[0]) ; j = numstr.index(initial_pos[1]) # Numerical initial position
- m = letstr.index(final_pos[0]); n = numstr.index(final_pos[1]) # Numerical final position
- if not (isinstance(board[i][j], ChessPiece)):
- raise InvalidMoveException('There is no chess piece here')
- piece = board[i][j]
- if self.rules(piece, i, j, m, n) != 1:
- raise('This move is not allowed')
- # Move the piece on the chessboard
- piece.movepiece(i, j, m, n, board)
- self.symbolboard = self.draw_board(self.objectboard.T)
- self.__class__.count += 1 # Increment the counter after each allowed move
- class ChessPiece: # This is the base class, all the other specific pieces inherit this class.
- def __init__(self, x, y, color):
- if not ((int == type(x)) and (int == type(y))):
- raise TypeError(' x and y should be integers!!')
- elif not ((x in range(8)) and (y in range(8))):
- raise ValueError('x and y positions should be between 0 and 7 inclusive')
- elif not ((str == type(color)) and (color in 'wb')):
- raise ValueError('Color should be "w" or "b"')
- self.pos_x = x
- self.pos_y = y
- self.color = color
- # IMPLEMENT PROMOTION HERE
- def movepiece(self, i, j, m, n, chessboard):
- self.pos_x = i
- self.pos_y = j
- chessboard[i][j] = 0 # Set the previous position to be zero
- chessboard[m][n] = self
- class King(ChessPiece):
- def __init__(self, x, y, color, chessboard):
- ChessPiece.__init__(self, x, y, color)
- self.symbol = 'K'
- self.has_already_moved = False
- chessboard[self.pos_x][self.pos_y] = self
- class Queen(ChessPiece):
- def __init__(self, x, y, color, chessboard):
- ChessPiece.__init__(self, x, y, color)
- self.symbol = 'Q'
- chessboard[self.pos_x][self.pos_y] = self
- class Rook(ChessPiece):
- def __init__(self, x, y, color, chessboard):
- ChessPiece.__init__(self, x, y, color)
- self.symbol = 'R'
- chessboard[self.pos_x][self.pos_y] = self
- class Bishop(ChessPiece):
- def __init__(self, x, y, color, chessboard):
- ChessPiece.__init__(self, x, y, color)
- self.symbol = 'B'
- chessboard[self.pos_x][self.pos_y] = self
- class Knight(ChessPiece):
- def __init__(self, x, y, color, chessboard):
- ChessPiece.__init__(self, x, y, color)
- self.symbol = 'N'
- chessboard[self.pos_x][self.pos_y] = self
- class Pawn(ChessPiece):
- def __init__(self, x, y, color, chessboard):
- ChessPiece.__init__(self, x, y, color)
- self.symbol = 'P'
- self.has_already_moved = False # To keep track if it just started moving
- chessboard[self.pos_x][self.pos_y] = self
- class Game:
- def __init__(self):
- self.chessboard = ChessBoard()
- self.chessboard.show_board(self.chessboard.symbolboard)
- self.chessboard.canvas.bind("<Button-1>", self.clickmove)
- self.clickct = 0
- #def __str__(self):
- #return str(print(self.chessboard))
- def play(self, move):
- try:
- self.chessboard.move(move)
- symbolboard = self.chessboard.symbolboard
- print(self.chessboard)
- self.chessboard.show_board(self.chessboard.symbolboard)
- except ChessException as error:
- print(error)
- def clickmove(self,event): # Implement click to move
- self.clickct = self.clickct % 2
- x = event.x
- y = event.y
- s1 = int(x / tile_width)
- s2 = 7 - int(y / tile_width)
- letstr = 'abcdefgh'
- numstr = '12345678'
- if (self.clickct == 0):
- self.initial_pos = letstr[s1] + numstr[s2]
- else:
- self.final_pos = letstr[s1] + numstr[s2]
- move = self.initial_pos + self.final_pos
- print('The move is', move, '\n')
- self.play(move)
- self.clickct += 1
- from chess import *
- g = Game()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement