class Ui: """Command line user interface Manages all the interaction with the user. """ color_dict = {0: "White", 1: "Black"} piece_type_dict = { 0: "\u2654\u265a", 1: "\u2655\u265b", 2: "\u2656\u265c", 3: "\u2657\u265d", 4: "\u2658\u265e", 5: "\u2659\u265f" } x_str2int = { "a": 0, "b": 1, "c": 2, "d": 3, "e": 4, "f": 5, "g": 6, "h": 7 } y_str2int = { "1": 0, "2": 1, "3": 2, "4": 3, "5": 4, "6": 5, "7": 6, "8": 7 } x_int2str = { 0: "a", 1: "b", 2: "c", 3: "d", 4: "e", 5: "f", 6: "g", 7: "h" } y_int2str = { 0: "1", 1: "2", 2: "3", 3: "4", 4: "5", 5: "6", 6: "7", 7: "8" } def __init__(self): self.board = Board() self.draw() def draw(self): """Draws the board configuration in the terminal""" display = " a b c d e f g h \n" + \ "________________________________ \n " # Loop over all x and y indices for j in range(8): display += " " + str(j + 1) + "|" for i in range(8): # Find the piece index for position [i, j] position_ij = Position(i, j) piece = self.board.find_piece(position_ij) if piece.color != None: display += " " + \ Ui.piece_type_dict[piece.type][piece.color] + " " else: # Draw an empty cell display += " - " # New line for different i value display += "|" + str(j + 1) + " \n " display += "_______________________________ \n" + \ " a b c d e f g h \n" self.board_string = display print(display) def turn(self): """"Performs a turn within ui""" selected_piece = self.select_piece() position = self.select_move(selected_piece) self.board.turn(selected_piece, position, self.draw, self.check, self.check_mate) def select_piece(self) -> Piece: """Asks the user to select a piece to make a move with""" question = Ui.color_dict[self.board.turn_color] + \ ", your turn! Please select a piece. \n" piece = Piece(None, None, None, None, None) while piece.color is None or piece.color != self.board.turn_color: coordinate = input(question) position = self.coordinate2position(coordinate) piece = self.board.find_piece(position) question = "No piece of yours at this field, try again! \n" return piece def select_move(self, selected_piece: int) -> Position: """Asks the user where to move the selected piece""" question = "The selected piece can move to " + \ self.moves2text(selected_piece) + "\n" coordinate = input(question) position = self.coordinate2position(coordinate) while not position in selected_piece.moves: question = "Your piece can't move to the selected field, try again! \n" coordinate = input(question) position = self.coordinate2position(coordinate) return position def moves2text(self, selected_piece: Piece) -> str: """Turns a list of positions into a string with coordinates""" text = "" for move in selected_piece.moves: text += self.position2coordinate(move) + ", " return text def coordinate2position(self, coordinate: str) -> Position: """Converts user input to a board position""" x = Ui.x_str2int[coordinate[0]] y = Ui.y_str2int[coordinate[1]] return Position(x, y) def position2coordinate(self, position: Position) -> str: """Converts user a position to a ui coordinate""" return Ui.x_int2str[position.x] + Ui.y_int2str[position.y] def check(self): """Function that notifies players when check""" print('Check!') def check_mate(self): """Function that notifies players when check mate""" print('Check mate! The game is over')
class Gui(): """Grafical user interface for playing chess""" font = 'Courier 20' color_dict = {0: '#b0b0b0', 1: '#ffffff'} piece_type_dict = { 0: { 0: '\u2654', 1: '\u265a' }, 1: { 0: '\u2655', 1: '\u265b' }, 2: { 0: '\u2656', 1: '\u265c' }, 3: { 0: '\u2657', 1: '\u265d' }, 4: { 0: '\u2658', 1: '\u265e' }, 5: { 0: '\u2659', 1: '\u265f' } } turn_color_dict = {0: 'White', 1: 'Black'} def __init__(self): # Init board self.board = Board() # Init root self.root = tk.Tk() # Create general structure self.board_frame = tk.Frame(self.root) self.board_frame.pack() self.test_frame = tk.Label(self.root, text='Welcome', font=Gui.font) self.test_frame.pack() self.user_input = tk.Entry(self.root, font=Gui.font) self.user_input.configure(state='readonly') self.user_input.pack() self.user_input_given = tk.IntVar(master=self.user_input, name='piece_type', value=-1) # Create buttons/fields self.buttons = [[], [], [], [], [], [], [], []] self.fields = [[], [], [], [], [], [], [], []] for x, y in product(range(8), range(8)): field_color = (x + y) % 2 self.fields[x].append( tk.Frame(self.board_frame, height=50, width=50, background=Gui.color_dict[field_color])) self.fields[x][y].propagate(False) self.fields[x][y].grid(column=x, row=8 - y) self.buttons[x].append( tk.Button(self.fields[x][y], background=Gui.color_dict[field_color], activebackground='#f2ff00', borderwidth=0, font='Courier 30')) self.buttons[x][y].pack(fill='both', expand=True) self.draw() self.select_piece() self.root.mainloop() def ask_promotion_type(self): """Asks the user which piece to promote""" self.user_input.bind('<Return>', self.promote2input) self.test_frame.configure(text='Promote to type:') self.user_input.configure(state='normal') self.reset_buttons() self.user_input_given.set(-1) self.user_input.wait_variable(name='piece_type') user_input = self.user_input_given.get() self.user_input.delete(0, len(self.user_input.get())) self.user_input.configure(state='readonly') return user_input def promote2input(self, event) -> int: """Gets the entered text from the entry box""" type_dict = { 'king': 0, 'queen': 1, 'rook': 2, 'bishop': 3, 'knight': 4, 'pawn': 5 } promotion_type = type_dict[self.user_input.get()] # self.board.promote(piece, promotion_type) self.user_input.bind('<Return>') self.user_input_given.set(promotion_type) def select_piece(self): """Select piece to move""" color = self.board.turn_color for x, rows in enumerate(self.buttons): for y, button in enumerate(rows): piece = self.board.find_piece(Position(x, y)) if piece.color == color and \ piece.moves != [] and \ piece.moves != None: func = partial(self.show_moves, piece) button.configure(command=func) def show_moves(self, piece: Piece): """Marks the fields where the selected piece can move to""" self.reset_buttons() for move in piece.moves: self.buttons[move.x][move.y].configure(background='#f2ff00', command=partial( self.select_move, piece, move)) def select_move(self, piece: Piece, position): """Runs when player selects where to move to""" self.reset_buttons() self.board.recalculate(piece, position, self.ask_promotion_type) self.board.delete_self_check() self.board.turn_counter += 1 self.board.turn_color = int(not self.board.turn_color) self.draw() if self.board.check == True: self.board.check_mate = \ self.board.ischeckmate(self.board.turn_color) if self.board.check_mate == True: self.test_frame.configure(text='Check mate!') else: self.test_frame.configure(text='Check!') else: message = Gui.turn_color_dict[self.board.turn_color] + \ ', it\'s your turn' self.test_frame.configure(text=message) self.select_piece() def draw(self): """Draws pieces on the board""" for (x, y) in product(range(8), range(8)): piece = self.board.find_piece(Position(x, y)) if piece.color != None: self.buttons[x][y].config( text=Gui.piece_type_dict[piece.type][piece.color]) else: self.buttons[x][y].config(text='') def reset_buttons(self): """Resets the buttons colors and commands""" for x, y in product(range(8), range(8)): button = self.buttons[x][y] button.configure(command=False, background=Gui.color_dict[(x + y) % 2])