Advertisement
Guest User

chessGUIinteractive

a guest
Jan 14th, 2016
137
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 14.82 KB | None | 0 0
  1. import numpy as np
  2. import tkinter as tk
  3. import os.path
  4. import os
  5. # CHECK, PROMOTION AND CASTLING
  6. tile_width = 60
  7. board_width = 8 * tile_width
  8. board_height = board_width
  9. pic_dir = "./Pictures" # These line has been modified to give the relative path
  10. DICT = {"black_tile":"black.gif",
  11.     "Bb":"blackbishop.gif",
  12.     "Bw":"whitebishop.gif",
  13.     "Kb":"blackking.gif",
  14.     "Kw":"whiteking.gif",
  15.     "Nb":"blackknight.gif",
  16.     "Nw":"whiteknight.gif",
  17.     "Pb":"blackpawn.gif",
  18.     "Pw":"whitepawn.gif",
  19.     "Qb":"blackqueen.gif",
  20.     "Qw":"whitequeen.gif",
  21.     "Rb":"blackrook.gif",
  22.     "Rw":"whiterook.gif",
  23.     "white_tile":"white.gif"
  24.     }
  25.  
  26. class ChessException(Exception):
  27.     """ Base class for chess exceptions"""
  28.     pass
  29.  
  30. class InvalidTurnException(ChessException):
  31.     def __init__(self, value):
  32.         self.parameter = value
  33.     def __str__(self):
  34.         return repr(self.parameter)
  35.        
  36. class InvalidMoveException(ChessException):
  37.     def __init__(self, value):
  38.         self.parameter = value
  39.     def __str__(self):
  40.         return repr(self.parameter)
  41.        
  42. class OccupiedFriendlySquareException(InvalidMoveException):
  43.     def __init__(self, value):
  44.         self.parameter = value
  45.     def __str__(self):
  46.         return repr(self.parameter)
  47.  
  48. class KingThreatenedSquareException(InvalidMoveException):
  49.     def __init__(self, value):
  50.         self.parameter = value
  51.     def __str__(self):
  52.         return repr(self.parameter)
  53.        
  54. class ObscurePathException(InvalidMoveException):
  55.     def __init__(self, value):
  56.         self.parameter = value
  57.     def __str__(self):
  58.         return repr(self.parameter)
  59.        
  60. class ChessBoard:
  61.     count = 0 # This is the counter to keep track of moves
  62.     def __init__(self):
  63.         self.objectboard = self.form_board()
  64.         self.symbolboard = self.draw_board(self.objectboard.T)
  65.         # Initialize the GUI
  66.         self.window = tk.Tk()
  67.         self.canvas = tk.Canvas(width = board_width, height = board_height)
  68.         self.canvas.pack()
  69.         self.images = {}
  70.         for image_file_name in DICT:
  71.             f = os.path.join(pic_dir, DICT[image_file_name])
  72.             if not os.path.exists(f):
  73.                 print("Error: Cannot find image file: %s at %s - aborting"%(DICT[image_file_name], f))
  74.                 exit(-1)
  75.             self.images[image_file_name]= tk.PhotoImage(file=f)    
  76.     def __str__(self):
  77.         string = ''
  78.          # Transpose is necessary to make the board as we are accustomed to
  79.         for i in reversed(range(8)): # It is reversed so that white is at the bottom
  80.             string += str(self.symbolboard[i])  + '\n'
  81.         return string
  82.        
  83.     def show_board(self, symbolboard):
  84.         for j in range(8):
  85.             y = j * tile_width
  86.             for i in range(8):
  87.                 x = i * tile_width
  88.                 if (i % 2 ==  ((1 + j) % 2)):  
  89.                     tile = self.images['black_tile']
  90.                 else:
  91.                     tile = self.images['white_tile']
  92.                 self.canvas.create_image(x, y, anchor = tk.NW,  image=tile)
  93.         for j in (range(8)):
  94.             for i in (range(8)):
  95.                 piece = symbolboard[i][j]
  96.                 if piece == '0 ':
  97.                     continue  #  There is no piece on this tile
  98.                 tile = self.images[piece]
  99.                 x = j * tile_width
  100.                 y = (7 - i) * tile_width
  101.                 self.canvas.create_image(x, y, anchor=tk.NW,  image = tile)
  102.     def form_board(self): # Forms the board and puts the pieces on the respective positions
  103.         board = np.zeros((8,8), dtype = object)
  104.         # Now we should put the pieces on the board
  105.         WhiteRook1 = Rook(0, 0, 'w', board)
  106.         WhiteRook2 = Rook(7, 0, 'w', board)
  107.         WhiteKnight1 = Knight(1, 0, 'w', board)
  108.         WhiteKnight2 = Knight(6, 0, 'w', board)
  109.         WhiteBishop1 = Bishop(2, 0, 'w', board)
  110.         WhiteBishop2 = Bishop(5, 0, 'w', board)
  111.         WhiteQueen = Queen(3, 0, 'w', board)
  112.         WhiteKing = King(4, 0, 'w', board)
  113.         # Now we should put the pawns
  114.         for i in range(8):
  115.             exec("WPawn" + str(i+1)  + "= Pawn(i, 1, 'w', board)")  
  116.         # This syntax is for changing variable names
  117.         # Now put the black pieces
  118.         BlackRook1 = Rook(0, 7, 'b', board)
  119.         BlackRook2 = Rook(7, 7, 'b', board)
  120.         BlackKnight1 = Knight(1, 7, 'b', board)
  121.         BlackKnight2 = Knight(6, 7, 'b', board)
  122.         BlackBishop1 = Bishop(2, 7, 'b', board)
  123.         BlackBishop2 = Bishop(5, 7, 'b', board)
  124.         BlackQueen = Queen(3, 7, 'b', board)
  125.         BlackKing = King(4, 7, 'b', board)
  126.         # Now we should put the pawns
  127.         for i in range(8):
  128.             exec("BPawn" + str(i+1)  + "= Pawn(i, 6, 'b', board)")  
  129.         return board
  130.        
  131.     def draw_board(self, board):
  132.         func_sym_col = np.vectorize(self.retrieve_piece)
  133.         symbolic_board = func_sym_col(board)
  134.         return symbolic_board
  135.        
  136.     @staticmethod # This method does not need to access class data
  137.     def retrieve_piece(piece):
  138.         if isinstance(piece, ChessPiece):
  139.             return str(piece.symbol+piece.color)
  140.         else:
  141.             return '0 '
  142.            
  143.     def rules(self, piece, i, j, m, n):
  144.         board = self.objectboard
  145.         #symboard = self.draw_board(board)
  146.         if ((self.__class__.count % 2) == 0):
  147.             if (piece.color == 'b'):
  148.                 raise InvalidTurnException('It is Whites turn to play')
  149.         else:
  150.             if (piece.color == 'w'):
  151.                 raise InvalidTurnException('It is Blacks turn to play')
  152.         piece_type = piece.symbol # Rules depend on the piece
  153.         # Implement check
  154.         check_new_pos = 0 # We should modify this write a loop over other pieces
  155.         opponent_king = 0
  156.         auxboard = []
  157.        
  158.         check1 = ((m - i) >= 0)
  159.         check2 =  ((n - j) >= 0)
  160.  
  161.         if piece_type == 'K':
  162.             if (abs(i - m) > 1):
  163.                 raise InvalidMoveException('This is not a valid move for the King')
  164.             elif (abs(j - n) > 1) :
  165.                 raise InvalidMoveException('This is not a valid move for the King')
  166.             elif check_new_pos:
  167.                 raise KingThreatenedSquareException('The King cannot move to a threatened square!!!')
  168.             elif opponent_king:
  169.                 raise KingThreatenedSquareException('You cannot go too close to the opponent king')
  170.          # Castling implementation
  171.          
  172.         elif piece_type == 'Q':
  173.             if not ((abs((i - m) / (j - n)) == 1) or ((i - m) == 0) or ((j - n) == 0)):
  174.                 raise InvalidMoveException('The queen cannot move like this')
  175.             if (i - m) == 0:
  176.                 if check2:
  177.                     auxboard = board[i][j+1:n]
  178.                 else:
  179.                     auxboard = board[i][n+1:j]
  180.             elif (j - n) == 0:
  181.                 if check1:
  182.                     auxboard = board[i+1:m][j]
  183.                 else:
  184.                     auxboard = board[m+1:i][j]
  185.             else:
  186.                 if check1 and check2:
  187.                     for ct in range(m - i - 1):
  188.                         auxboard.append(board[i + 1 + ct][j + 1 + ct])
  189.                 elif check1 and (not check2):
  190.                     for ct in range(m - i  - 1):
  191.                         auxboard.append(board[i + 1 + ct][j - 1 - ct])
  192.                 elif (not check1) and check2:
  193.                     for ct in range(i - m - 1):
  194.                         auxboard.append(board[i - 1 - ct][j + 1 + ct])
  195.                 elif (not check1) and (not check2):
  196.                     for ct in range(i - m - 1):
  197.                         auxboard.append(board[i - 1 - ct][j - 1 - ct])
  198.             if not (all(p == 0 for p in auxboard)):
  199.                 raise ObscurePathException('The path is obscured')
  200.                
  201.         elif piece_type == 'R':
  202.             if not (((i - m) == 0) or ((j - n) == 0)):
  203.                 raise InvalidMoveException('The rook cannot move like this')
  204.             if (i - m) == 0:
  205.                 if check2:
  206.                     auxboard = board[i][j+1:n]
  207.                 else:
  208.                     auxboard = board[i][n+1:j]
  209.             elif (j - n) == 0:
  210.                 if check1:
  211.                     auxboard = board[i+1:m][j]
  212.                 else:
  213.                     auxboard = board[m+1:i][j]
  214.             if not (all(p == 0 for p in auxboard)):
  215.                 raise ObscurePathException('The path is obscured')
  216.  
  217.         elif piece_type == 'B':
  218.             if not (abs((i - m) / (j - n)) == 1):
  219.                 raise InvalidMoveException('The bishop cannot move like this')
  220.             if check1 and check2:
  221.                 for ct in range(m - i - 1):
  222.                     auxboard.append(board[i + 1 + ct][j + 1 + ct])
  223.             elif check1 and (not check2):
  224.                 for ct in range(m - i  - 1):
  225.                     auxboard.append(board[i + 1 + ct][j - 1 - ct])
  226.             elif (not check1) and check2:
  227.                 for ct in range(i - m - 1):
  228.                     auxboard.append(board[i - 1 - ct][j + 1 + ct])
  229.             elif (not check1) and (not check2):
  230.                 for ct in range(i - m - 1):
  231.                     auxboard.append(board[i - 1 - ct][j - 1 - ct])
  232.             if not (all(p == 0 for p in auxboard)):
  233.                 raise ObscurePathException('The path is obscured')
  234.                
  235.         elif piece_type == 'N': # The path may be obscured this time
  236.             if not (((abs(i - m) == 2) and (abs(j - n) == 1)) or  ((abs(i - m) == 1) and (abs(j - n) == 2))):
  237.                 raise InvalidMoveException('The knight cannot move like this')
  238.                
  239.         elif piece_type == 'P':
  240.             if piece.color == 'w':
  241.                 if piece.has_already_moved == 0:
  242.                     if not(((n - j) == 2) or ((n - j) == 1) and ((i - m) == 0) ):
  243.                         raise InvalidMoveException('The pawn cannot move like this')
  244.                     elif (board[m][n] != 0) or (board[m][n - 1] != 0 if  (n - j) == 2 else False):
  245.                         if ((abs(i - m) == 1)  and (n - j == 1)):
  246.                             pass
  247.                         else:
  248.                             raise InvalidMoveException('The pawn cannot attack forward')
  249.                            
  250.                 else: # Pawn has moved
  251.                     if not((n - j) == 1):
  252.                         raise InvalidMoveException('The pawn cannot move like this')
  253.                     elif (board[m][n] != 0):
  254.                         if ((abs(i - m) == 1)  and (n - j == 1)):
  255.                             pass
  256.                         else:
  257.                             raise InvalidMoveException('The pawn cannot attack forward')
  258.                            
  259.             else: # Black pawn
  260.                 if piece.has_already_moved == 0:
  261.                     if not(((n - j) == -2) or ((n - j) == -1) and ((i - m) == 0)):
  262.                         raise InvalidMoveException('The pawn cannot move like this')
  263.                     elif (board[m][n] != 0) or (board[m][n - 1] != 0 if  (n - j) == 2 else False):
  264.                         if ((abs(i - m) == 1)  and (n - j == -1)):
  265.                             pass
  266.                         else:
  267.                             raise InvalidMoveException('The pawn cannot attack forward')
  268.                            
  269.                     elif (board[m][n] != 0) or (board[m][n + 1] != 0 if  (n - j) == -2 else False):
  270.                         raise InvalidMoveException('The pawn cannot attack forward')
  271.                 else: # Pawn has moved
  272.                     if not((n - j) == -1):
  273.                         raise InvalidMoveException('The pawn cannot move like this')
  274.                     elif (board[m][n] != 0):
  275.                         if ((abs(i - m) == 1)  and (n - j == -1)):
  276.                             pass
  277.                         else:
  278.                             raise InvalidMoveException('The pawn cannot attack forward')
  279.                        
  280.         # Implement one cannot move to a square containing same color piece
  281.         if board[m][n] != 0: # There is a piece in the final position
  282.             if board[i][j].color == board[m][n].color:# Two pieces are of the same color
  283.                 raise OccupiedFriendlySquareException("You cannot go to your own pieces location")
  284.             elif board[m][n].symbol == 'K':# The opponent king is in the location
  285.                 raise InvalidMoveException("You cannot eat the KING")
  286.         if ((piece_type == 'P') or (piece_type == 'K')):
  287.             piece.has_already_moved = True
  288.         return True
  289.        
  290.     def move(self, position):
  291.         # These two strings are for board coordinates
  292.         letstr = 'abcdefgh'
  293.         numstr = '12345678'
  294.         board = self.objectboard
  295.         if not (len(position) == 4):
  296.             raise ValueError('The position string should consist of 4 characters');
  297.         # Get the final and initial positions
  298.         initial_pos = position[:2]
  299.         final_pos = position[-2:]
  300.         # First perform the checks
  301.         if not (str == type(initial_pos) and (str == type(final_pos))):     # Check if the arguments are strings
  302.             raise TypeError('The supplied positions should be strings!')
  303.         elif not ((initial_pos[0] in letstr) and (initial_pos[1] in numstr)): # Check if they fulfill the condition to be on the board
  304.             raise InvalidMoveException('The initial position values should be between a1 and h8')
  305.         elif not ((final_pos[0] in letstr) and (final_pos[1] in numstr)): # Check if they fulfill the condition to be on the board
  306.             raise InvalidMoveException('The final position values should be between a1 and h8')
  307.         elif initial_pos == final_pos:
  308.             raise InvalidMoveException('Final position should be different from the initial position')
  309.         # Now determine if there is a piece on the initial square
  310.         i = letstr.index(initial_pos[0]) ; j = numstr.index(initial_pos[1]) # Numerical initial position
  311.         m = letstr.index(final_pos[0]); n = numstr.index(final_pos[1]) # Numerical final position
  312.         if not (isinstance(board[i][j], ChessPiece)):
  313.             raise InvalidMoveException('There is no chess piece here')
  314.         piece = board[i][j]
  315.         if self.rules(piece, i, j, m, n) != 1:
  316.             raise('This move is not allowed')
  317.         # Move the piece on the chessboard
  318.         piece.movepiece(i, j, m, n, board)
  319.         self.symbolboard = self.draw_board(self.objectboard.T)
  320.         self.__class__.count += 1 # Increment the counter after each allowed move
  321.  
  322. class ChessPiece: # This is the base class, all the other specific pieces inherit this class.
  323.     def __init__(self, x, y, color):
  324.         if not ((int == type(x)) and (int == type(y))):
  325.             raise TypeError(' x and y should be integers!!')
  326.         elif not ((x in range(8)) and (y in range(8))):
  327.             raise ValueError('x and y positions should be between 0 and 7 inclusive')
  328.         elif not ((str == type(color)) and (color in 'wb')):
  329.             raise ValueError('Color should be "w" or "b"')
  330.         self.pos_x = x
  331.         self.pos_y = y
  332.         self.color = color
  333.         # IMPLEMENT PROMOTION HERE
  334.     def movepiece(self, i, j, m, n, chessboard):
  335.         self.pos_x = i
  336.         self.pos_y = j
  337.         chessboard[i][j] = 0 # Set the previous position to be zero
  338.         chessboard[m][n] = self
  339.  
  340. class King(ChessPiece):
  341.         def __init__(self, x, y, color, chessboard):
  342.             ChessPiece.__init__(self, x, y, color)
  343.             self.symbol = 'K'
  344.             self.has_already_moved = False
  345.             chessboard[self.pos_x][self.pos_y] = self
  346.  
  347. class Queen(ChessPiece):
  348.         def __init__(self, x, y, color, chessboard):
  349.             ChessPiece.__init__(self, x, y, color)
  350.             self.symbol = 'Q'
  351.             chessboard[self.pos_x][self.pos_y] = self
  352.  
  353. class Rook(ChessPiece):
  354.         def __init__(self, x, y, color, chessboard):
  355.             ChessPiece.__init__(self, x, y, color) 
  356.             self.symbol = 'R'
  357.             chessboard[self.pos_x][self.pos_y] = self
  358.  
  359. class Bishop(ChessPiece):
  360.         def __init__(self, x, y, color, chessboard):
  361.             ChessPiece.__init__(self, x, y, color)
  362.             self.symbol = 'B'
  363.             chessboard[self.pos_x][self.pos_y] = self
  364.            
  365. class Knight(ChessPiece):
  366.         def __init__(self, x, y, color, chessboard):
  367.             ChessPiece.__init__(self, x, y, color)
  368.             self.symbol = 'N'
  369.             chessboard[self.pos_x][self.pos_y] = self
  370.            
  371. class Pawn(ChessPiece):
  372.         def __init__(self, x, y, color, chessboard):
  373.             ChessPiece.__init__(self, x, y, color)
  374.             self.symbol = 'P'
  375.             self.has_already_moved = False # To keep track if it just started moving
  376.             chessboard[self.pos_x][self.pos_y] = self
  377.  
  378. class Game:
  379.     def __init__(self):
  380.         self.chessboard = ChessBoard()
  381.         self.chessboard.show_board(self.chessboard.symbolboard)
  382.         self.chessboard.canvas.bind("<Button-1>", self.clickmove)
  383.         self.clickct = 0
  384.        
  385.     #def __str__(self):
  386.         #return str(print(self.chessboard))
  387.        
  388.     def play(self, move):
  389.             try:
  390.                 self.chessboard.move(move)
  391.                 symbolboard = self.chessboard.symbolboard
  392.                 print(self.chessboard)
  393.                 self.chessboard.show_board(self.chessboard.symbolboard)
  394.             except ChessException as error:
  395.                 print(error)
  396.  
  397.     def clickmove(self,event): # Implement click to move
  398.         self.clickct = self.clickct % 2
  399.         x = event.x
  400.         y = event.y
  401.         s1 = int(x / tile_width)
  402.         s2 = 7 - int(y / tile_width)
  403.         letstr = 'abcdefgh'
  404.         numstr = '12345678'
  405.         if (self.clickct == 0):
  406.             self.initial_pos = letstr[s1] + numstr[s2]
  407.         else:
  408.             self.final_pos = letstr[s1] + numstr[s2]
  409.             move = self.initial_pos + self.final_pos
  410.             print('The move is', move, '\n')
  411.             self.play(move)
  412.         self.clickct += 1
  413.  
  414. from chess import *
  415.  
  416. g = Game()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement