Facebook
From عرشیا, 1 Month ago, written in Python.
Embed
Download Paste or View Raw
Hits: 155
  1. import tkinter as tk
  2. from tkinter import messagebox
  3. from tkinter import Button
  4. from functools import partial
  5. class Position:
  6.     def __init__(self, row, col):
  7.         self.row = row
  8.         self.col = col
  9.     def match(self,list_pos):
  10.         for pos in list_pos:
  11.             if pos.row == self.row and pos.col == self.col:
  12.                 return True
  13.         return False
  14. class Piece:
  15.     def __init__(self, color, board, position=None):
  16.         self.color = color
  17.         self.board = board
  18.         self.has_moved = False
  19.         self.position = position
  20.     def __str__(self):
  21.         pass
  22. class King(Piece):
  23.     def __init__(self,color,board,position=None):
  24.         super().__init__(color,board,position)
  25.         self.piece_type = "king"
  26.        
  27.     def possible_moves(self):
  28.         moves = []
  29.         offsets = [(1, 0), (0, 1), (-1, 0), (0, -1),
  30.                    (1, 1), (-1, 1), (1, -1), (-1, -1)]
  31.         for dr, dc in offsets:
  32.             new_pos = Position(self.position.row + dr, self.position.col + dc)
  33.             if self.board.is_inside_board(new_pos) and (self.board.is_square_empty(new_pos) or self.board.is_enemy_piece(new_pos, self.color)):
  34.                 moves.append(new_pos)
  35.         # Castling
  36.         if not self.board.board[self.position.row][self.position.col].has_moved:
  37.             # Check kingside castling
  38.             if self.board.board[self.position.row][7] and not self.board.board[self.position.row][7].has_moved:
  39.                 if all(self.board.is_square_empty(Position(self.position.row, c)) for c in range(self.position.col + 1, 7)):
  40.                     moves.append(Position(self.position.row, self.position.col + 2))
  41.             # Check queenside castling
  42.             if  self.board.board[self.position.row][0] and not self.board.board[self.position.row][0].has_moved:
  43.                 if all(self.board.is_square_empty(Position(self.position.row, c)) for c in range(1, self.position.col)):
  44.                     moves.append(Position(self.position.row, self.position.col - 2))
  45.         return moves
  46.     def move(self,end_pos):
  47.         a = self.possible_moves()
  48.         for pos in a:
  49.             if pos.row == end_pos.row and pos.col == end_pos.col:
  50.                 return True
  51.         return False
  52.     def __str__(self):
  53.         if self.color == "White":
  54.             return "K"
  55.         return "k"
  56. class Bishop(Piece):
  57.     def __init__(self,color,board,position=None):
  58.         super().__init__(color,board,position)
  59.         self.piece_type = "bishop"
  60.     def possible_moves(self):
  61.         moves = []
  62.         directions = [(-1, -1), (-1, 1), (1, 1), (1, -1)]
  63.         for dr, dc in directions:
  64.             temp = self.position
  65.             while True:
  66.                 new_pos = Position(temp.row + dr, temp.col + dc)
  67.                 temp = new_pos
  68.                 if self.board.is_inside_board(new_pos) == False:
  69.                     break
  70.                 if self.board.is_inside_board(new_pos) and (self.board.is_square_empty(new_pos) or self.board.is_enemy_piece(new_pos, self.color)):
  71.                     moves.append(new_pos)
  72.                 if self.board.is_enemy_piece(new_pos, self.color):
  73.                     break
  74.         return moves
  75.     def move(self,end_pos):
  76.         a = self.possible_moves()
  77.         for pos in a:
  78.             if pos.row == end_pos.row and pos.col == end_pos.col:
  79.                 return True
  80.         return False
  81.     def __str__(self):
  82.         if self.color == "White":
  83.             return "B"
  84.         return "b"
  85. class Pawn(Piece):
  86.     def __init__(self,color,board,position=None):
  87.         super().__init__(color,board,position)
  88.         self.piece_type = "pawn"
  89.     def possible_moves(self):
  90.         moves = []
  91.         direction = 1 if self.color == "White" else -1
  92.         start_row = 1 if self.color == "White" else 6
  93.         # Moves for regular pawn advance
  94.         temp = self.position
  95.         count = 0
  96.         while count < 2:
  97.             new_pos = Position(temp.row + direction, temp.col)
  98.             temp = new_pos
  99.             if self.board.is_inside_board(new_pos) and self.board.is_square_empty(new_pos):
  100.                 moves.append(new_pos)
  101.             else:
  102.                 break
  103.             count += 1
  104.         # Moves for capturing diagonally
  105.         temp = self.position
  106.         new_pos = Position(temp.row + direction, temp.col - 1)
  107.         if self.board.is_inside_board(new_pos):
  108.             if self.board.is_enemy_piece(new_pos, self.color):
  109.                 moves.append(new_pos)
  110.         new_pos = Position(temp.row + direction, temp.col + 1)
  111.         if self.board.is_inside_board(new_pos):
  112.             if self.board.is_enemy_piece(new_pos, self.color):
  113.                 moves.append(new_pos)
  114.         return moves
  115.     def move(self,end_pos):
  116.         a = self.possible_moves()
  117.         for pos in a:
  118.             if pos.row == end_pos.row and pos.col == end_pos.col:
  119.                 return True
  120.         return False
  121.     def __str__(self):
  122.         if self.color == "White":
  123.             return "P"
  124.         return "p"
  125. class Rook(Piece):
  126.      def __init__(self,color,board,positi
  127.         super().__init__(color,board,position)
  128.         self.piece_type = "rook"
  129.     def possible_moves(self):
  130.         moves = []
  131.          directi 0), (-1, 0), (0, 1), (0, -1)]
  132.         for dr, dc in directions:
  133.             temp = self.position
  134.             while True:
  135.                 new_pos = Position(temp.row + dr, temp.col + dc)
  136.                 temp = new_pos
  137.                 if self.board.is_inside_board(new_pos) == False:
  138.                     break
  139.                 if self.board.is_inside_board(new_pos) and (self.board.is_square_empty(new_pos) or self.board.is_enemy_piece(new_pos, self.color)):
  140.                     moves.append(new_pos)
  141.                 if self.board.is_enemy_piece(new_pos, self.color):
  142.                     break
  143.         return moves
  144.     def move(self,end_pos):
  145.         a = self.possible_moves()
  146.         for pos in a:
  147.             if pos.row == end_pos.row and pos.col == end_pos.col:
  148.                 return True
  149.         return False
  150.     def __str__(self):
  151.         if self.color == "White":
  152.             return "R"
  153.         return "r"
  154.  
  155. class Knight(Piece):
  156.      def __init__(self,color,board,positi
  157.         super().__init__(color,board,position)
  158.         self.piece_type = "knight"
  159.     def possible_moves(self):
  160.         moves = []
  161.         ends = [(-2, 1), (-2, -1), (2, -1), (2, 1), (1, 2), (-1, 2), (1, -2), (-1, -2)]
  162.         temp = self.position
  163.         for er, ec in ends:
  164.             new_pos = Position(temp.row + er, temp.col + ec)
  165.             print(new_pos.row, new_pos.col)
  166.             if self.board.is_inside_board(new_pos) and (self.board.is_square_empty(new_pos) or self.board.is_enemy_piece(new_pos, self.color)):
  167.                 moves.append(new_pos)
  168.  
  169.         return moves
  170.     def move(self,end_pos):
  171.         a = self.possible_moves()
  172.         for pos in a:
  173.             if pos.row == end_pos.row and pos.col == end_pos.col:
  174.                 return True
  175.         return False
  176.     def __str__(self):
  177.         if self.color == "White":
  178.             return "N"
  179.         return "n"
  180.            
  181. class Queen(Piece):
  182.      def __init__(self,color,board,positi
  183.         super().__init__(color,board,position)
  184.         self.piece_type = "queen"
  185.     def possible_moves(self):
  186.         moves = []
  187.          directi -1), (-1, 1), (1, 1), (1, -1), (1, 0), (-1, 0), (0, 1), (0, -1)]
  188.         for dr, dc in directions:
  189.             temp = self.position
  190.             while True:
  191.                 new_pos = Position(temp.row + dr, temp.col + dc)
  192.                 temp = new_pos
  193.                 if self.board.is_inside_board(new_pos):
  194.                     if self.board.is_square_empty(new_pos) or self.board.is_enemy_piece(new_pos, self.color):
  195.                         moves.append(new_pos)
  196.                 if not self.board.is_inside_board(new_pos):
  197.                     break
  198.                 if self.board.is_enemy_piece(new_pos, self.color) or self.board.is_inside_board(new_pos) == False:
  199.                     break
  200.         return moves
  201.     def move(self,end_pos):
  202.         a = self.possible_moves()
  203.         for pos in a:
  204.             if pos.row == end_pos.row and pos.col == end_pos.col:
  205.                 return True
  206.         return False
  207.     def __str__(self):
  208.         if self.color == "White":
  209.             return "Q"
  210.         return "q"
  211. class Board:
  212.     def __init__(self):
  213.         self.board = [[None for _ in range(8)] for _ in range(8)] #initialize the board
  214.          self.butt for _ in range(8)] for _ in range(8)]
  215.         self.left_click = [[0 for _ in range(8)] for _ in range(8)]
  216.         self.right_click = [[0 for _ in range(8)] for _ in range(8)]
  217.         for i in range(8):
  218.             for j in range(8):
  219.                 bt = Button(master, text = f'{i} {j}', height = 5, width = 10)
  220.                 bt.bind("<Button-1>", partial(self.lft, i, j))
  221.                 bt.bind("<Button-2>", partial(self.rgt, i, j))
  222.                 self.buttons[i][j] = bt
  223.                 bt.grid(row = i, column = j)
  224.     def lft(self, i, j):
  225.         # global current_player
  226.         for ii in range(8):
  227.             for jj in range(8):
  228.                 self.left_click[ii][jj] = 0
  229.         # if self.board[i][j].color == current_player:
  230.             self.left_click[i][j] = 1
  231.     def rgt(self, i, j):
  232.         flag = False
  233.         for ii in range(8):
  234.             for jj in range(8):
  235.                 if self.left_click[ii][jj] == 1:
  236.                     flag = True
  237.         if flag == True:
  238.             for ii in range(8):
  239.                 for jj in range(8):
  240.                     self.right_click[ii][jj] = 0
  241.             self.right_click[i][j] = 1
  242.  
  243.     def place_piece(self, piece, position):
  244.         self.board[position.row][position.col] = piece
  245.         self.buttons[position.row][position.col].config(text = f'{piece.piece_type}')
  246.         piece.position = position
  247.  
  248.     def remove_piece(self, piece):
  249.         self.board[piece.position.row][piece.position.col] = None
  250.         self.buttons[piece.position.row][piece.position.col].config(text = '')
  251.  
  252.     def move_piece(self, start_pos, end_pos):
  253.         piece = self.board[start_pos.row][start_pos.col]
  254.         if piece:
  255.             if piece.move(end_pos):
  256.                 #TODO (remove piece, place the piece at the end_pos and set has_moved to True)
  257.                 self.remove_piece(piece)
  258.                 self.place_piece(piece, end_pos)
  259.                 piece.has_moved = True
  260.                 piece.position = end_pos
  261.                 return True
  262.         else:
  263.             print("No piece at the starting position.")
  264.             return False
  265.  
  266.     def is_square_empty(self, position):
  267.         return self.board[position.row][position.col] is None
  268.  
  269.     def is_enemy_piece(self, position, color):
  270.         if not self.is_square_empty(position):
  271.             if self.board[position.row][position.col].color == color:
  272.                 return False
  273.             return True
  274.         return False
  275.            
  276.  
  277.  
  278.     def is_inside_board(self, position):
  279.         if position.row > 7 or position.col > 7 or position.row < 0 or position.col < 0:
  280.             return False
  281.         return True
  282.  
  283.     def print_board(self):
  284.         print(" | a b c d e f g h")
  285.         print("------------------")
  286.         for i, row in enumerate(self.board):
  287.             row_str = str(i) + "| "
  288.             for piece in row:
  289.                 if piece:
  290.                     row_str += f"{piece} "
  291.                 else:
  292.                     row_str += ". "
  293.             print(row_str)
  294.         print("\n")
  295. class ChessSet:
  296.     def __init__(self):
  297.         self.board = Board()
  298.         self.setup_board()
  299.  
  300.     def setup_board(self):
  301.         # Place white pieces
  302.         self.board.place_piece(Rook("White",self.board), Position(0, 0))
  303.         self.board.place_piece(Knight("White",self.board), Position(0, 1))
  304.         self.board.place_piece(Bishop("White",self.board), Position(0, 2))
  305.         self.board.place_piece(Queen("White",self.board), Position(0, 3))
  306.         self.board.place_piece(King("White",self.board), Position(0, 4))
  307.         self.board.place_piece(Bishop("White",self.board), Position(0, 5))
  308.         self.board.place_piece(Knight("White",self.board), Position(0, 6))
  309.         self.board.place_piece(Rook("White",self.board), Position(0, 7))
  310.         for col in range(8):
  311.             self.board.place_piece(Pawn("White", self.board), Position(1, col))
  312.  
  313.  
  314.         # Place black pieces
  315.         self.board.place_piece(Rook("Black",self.board), Position(7, 0))
  316.         self.board.place_piece(Knight("Black",self.board), Position(7, 1))
  317.         self.board.place_piece(Bishop("Black",self.board), Position(7, 2))
  318.         self.board.place_piece(Queen("Black",self.board), Position(7, 3))
  319.         self.board.place_piece(King("Black",self.board), Position(7, 4))
  320.         self.board.place_piece(Bishop("Black",self.board), Position(7, 5))
  321.         self.board.place_piece(Knight("Black",self.board), Position(7, 6))
  322.         self.board.place_piece(Rook("Black",self.board), Position(7, 7))
  323.         for col in range(8):
  324.             self.board.place_piece(Pawn("Black", self.board), Position(6, col))
  325.  
  326.     def print_board(self):
  327.         self.board.print_board()
  328. class Chess:
  329.     def __init__(self):
  330.         self.chess_set = ChessSet()
  331.  
  332.     def start_game(self):
  333.         # print("Welcome to Chess!\n")
  334.         current_player = "White"
  335.         bt = Button(master, text = f"{current_player}'s turn:")
  336.         bt.grid(row = 4, column = 8)
  337.         while True:
  338.             self.chess_set.print_board()
  339.             if self.is_checkmate(current_player):
  340.                 # print(current_player + " lost")
  341.                 messagebox.showinfo("finish", f'{current_player} lost')
  342.                 break
  343.             # print(f"\n{current_player}'s turn:")
  344.             bt.config(text = f"{current_player}'s turn:")
  345.             while True:
  346.                 # start_pos = input("Enter the position of the piece you want to move (e.g., 'a2'): ")
  347.                 end_pos = None
  348.                 while end_pos == None:
  349.                     for i in range(8):
  350.                         for j in range(8):
  351.                             if self.chess_set.board.right_click[i][j] == 1:
  352.                                 end_pos = Position(i, j)
  353.                
  354.                 for i in range(8):
  355.                     for j in range(8):
  356.                         if self.chess_set.board.left_click[i][j] == 1:
  357.                             start_pos = Position(i, j)
  358.                 # start_pos = Position(1,0)
  359.                 # end_pos = Position(2,0)
  360.                 print("salam")
  361.                 # for i in self.chess_set.board.board[start_pos.row][start_pos.col].possible_moves():
  362.                 #     print(i.col, i.row)
  363.                 if self.chess_set.board.board[start_pos.row][start_pos.col]:
  364.                     if not self.chess_set.board.board[start_pos.row][start_pos.col].move(end_pos):
  365.                         messagebox.showerror("wrong move", "cant move")
  366.                         continue
  367.                 self.chess_set.board.move_piece(start_pos, end_pos)
  368.                 if self.is_check(current_player):
  369.                     self.chess_set.board.move_piece(end_pos, start_pos)
  370.                     continue
  371.                 current_player = "Black" if current_player == "White" else "White"
  372.                 break
  373.             break      
  374.  
  375.  
  376.             #TODO - check if the input is according to the expected format
  377.             #TODO - move the piece if it is possible, otherwise notify the user to select other moves
  378.             #TODO - print the board
  379.             #TODO - check if the king is in checkmate (much simpler than real-world chess)
  380.             #TODO - check the king is in check
  381.             #TODO - switch the turns
  382.  
  383.     def is_valid_input(self, start_pos, end_pos):
  384.         #TODO - check each of the inputs have length of two elements and the first letter is an alphabet and the second one is a digit
  385.         if len(start_pos) != 2 or len(end_pos) != 2:
  386.             return False
  387.         c = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']
  388.         if not (start_pos[0] in c) or not (end_pos[0] in c):
  389.             return False
  390.         c = ['0', '1', '2', '3', '4', '5', '6', '7']
  391.         if not (start_pos[1] in c) or not (end_pos[1] in c):
  392.             return False
  393.         return True
  394.  
  395.     def is_check(self, current_player):
  396.         #TODO - find current_player's king on the board, check if the king is in check
  397.         enemy = "Black" if current_player == "White" else "White"
  398.         for i in range(8):
  399.             for j in range(8):
  400.                 piece = self.chess_set.board.board[i][j]
  401.                 if piece:
  402.                     if piece.color == enemy:
  403.                         if piece.possible_moves():
  404.                             for pos in piece.possible_moves():
  405.                                 if self.chess_set.board.board[pos.row][pos.col]:
  406.                                     if self.chess_set.board.board[pos.row][pos.col].piece_type == "king":
  407.                                         return True
  408.         return False
  409.  
  410.  
  411.     def is_checkmate(self, current_player):
  412.         # For simplicity, we consider losing the king as checkmate
  413.         enemy = "Black" if current_player == "White" else "White"
  414.         for i in range(8):
  415.             for j in range(8):
  416.                 piece = self.chess_set.board.board[i][j]
  417.                 if piece and piece.piece_type == "king" and piece.color == enemy:
  418.                     return False
  419.         return True
  420.    
  421.     def from_algebraic(self,algebraic_notation):
  422.         col = ord(algebraic_notation[0]) - ord('a')
  423.         row = int(algebraic_notation[1])
  424.         return Position(row,col)
  425.  
  426. if __name__ == "__main__":
  427.     master = tk.Tk()
  428.     master.geometry("850x680")
  429.     chess_game = Chess()
  430.     chess_game.start_game()
  431.     master.mainloop()