diff --git a/src/apps/pages/programs/Games/Chess/ChessBoard.py b/src/apps/pages/programs/Games/Chess/ChessBoard.py new file mode 100644 index 00000000..b322a877 --- /dev/null +++ b/src/apps/pages/programs/Games/Chess/ChessBoard.py @@ -0,0 +1,218 @@ +from pieces.Bishop import Bishop +from pieces.King import King +from pieces.Knight import Knight +from pieces.Pawn import Pawn +from pieces.Queen import Queen + +from pieces.Rook import Rook + + +class ChessBoard: + def __init__(self): + self.board = [[None for _ in range(8)] for _ in range(8)] + for i in range(8): + self.board[i][1] = Pawn('w', (i, 1)) + self.board[i][6] = Pawn('b', (i, 6)) + + self.board[0][7] = Rook('b', (0, 7)) + self.board[7][7] = Rook('b', (7, 7)) + self.board[1][7] = Knight('b', (1, 7)) + self.board[6][7] = Knight('b', (6, 7)) + self.board[2][7] = Bishop('b', (2, 7)) + self.board[5][7] = Bishop('b', (5, 7)) + self.board[4][7] = King('b', (4, 7)) + self.board[3][7] = Queen('b', (3, 7)) + + self.board[0][0] = Rook('w', (0, 0)) + self.board[7][0] = Rook('w', (7, 0)) + self.board[1][0] = Knight('w', (1, 0)) + self.board[6][0] = Knight('w', (6, 0)) + self.board[2][0] = Bishop('w', (2, 0)) + self.board[5][0] = Bishop('w', (5, 0)) + self.board[4][0] = King('w', (4, 0)) + self.board[3][0] = Queen('w', (3, 0)) + + self.curr_player = 'w' + + self.played_moves = [] + + def get_all_pieces(self): + """Returns list of all pieces on board""" + pieces = [] + for x in range(8): + for y in range(8): + if self.board[x][y]: + pieces.append(self.board[x][y]) + return pieces + + def get_curr_player_pieces(self): + """Returns all remaining pieces of current player""" + pieces = [] + for piece in self.get_all_pieces(): + if piece.color == self.curr_player: + pieces.append(piece) + return pieces + + def get_poss_moves_for(self, piece): + """Returns all possible moves for piece given""" + # NOTE: Must check for a Castle move if king is selected + if piece.name != 'King': + return piece.get_possible_moves(self.board) + else: + return piece.get_possible_moves(self.board) + self.get_castle_moves_for_curr_player() + + def get_piece_at(self, space): + """Returns piece at space""" + return self.board[space[0]][space[1]] + + def get_type_pieces_of_player(self, piece_name, player): + """Returns all pieces of type given of player given""" + pieces = [] + for row in self.board: + for space in row: + if space and space.name == piece_name and space.color == player: + pieces.append(space) + return pieces + + def move_piece(self, piece, new_position): + """Moves piece to new position AND changes has_moved to TRUE + Returns piece if piece taken, none if not""" + pos = piece.position + piece_to_take = self.board[new_position[0]][new_position[1]] + piece.move(new_position) + self.board[new_position[0]][new_position[1]] = piece + self.board[pos[0]][pos[1]] = None + if not piece.has_moved: + piece.has_moved = True + + if piece_to_take: + return piece_to_take + return None + + def non_permanent_move(self, piece, new_position): + """Moves piece and does NOT change has_moved to true. Used to check for checks/checkmates""" + pos = piece.position + piece.move(new_position) + self.board[new_position[0]][new_position[1]] = piece + self.board[pos[0]][pos[1]] = None + + def get_castle_moves_for_curr_player(self): + """Returns list of possible castle positions""" + castles = [] + king = self.get_type_pieces_of_player('King', self.curr_player)[0] + y = 0 if self.curr_player == 'w' else 7 + b = self.board + # Check king and rook have not moved + if b[0][y] and not b[0][y].has_moved and b[4][y] and not b[4][y].has_moved: + # Check no pieces in between rook and king + if all(not b[x][y] for x in range(1, 4)): + if not self.king_in_check(king, self.board): + castles.append((2, y)) + + if b[7][y] and not b[7][y].has_moved and b[4][y] and not b[4][y].has_moved: + if all(not b[x][y] for x in range(5, 7)): + if not self.king_in_check(king, self.board): + castles.append((6, y)) + + # Simulate both moves and check player is in check + for move in castles: + self.non_permanent_castle_king(king, move) + if self.king_in_check(king, self.board): + castles.remove(move) + # Uncastle pieces + self.uncastle_king(king) + + return castles + + def castle_king(self, king, new_king_position): + """Given king piece and one of the four king positions that can make a castle. Moves king to that position and + moves corresponding rook as well""" + # NEW_KING_POS = (2, 0), (6, 0), (2, 7), (6, 7) + corresponding_rook = {(2, 0): (0, 0), (6, 0): (7, 0), (2, 7): (0, 7), (6, 7): (7, 7)} + corresponding_rook_move = {(2, 0): (3, 0), (6, 0): (5, 0), (2, 7): (3, 7), (6, 7): (5, 7)} + rook_pos = corresponding_rook[new_king_position] + rook = self.board[rook_pos[0]][rook_pos[1]] + self.move_piece(king, new_king_position) + self.move_piece(rook, corresponding_rook_move[new_king_position]) + + def non_permanent_castle_king(self, king, new_king_position): + """Given king piece and one of the four king positions that can make a castle. Moves king to that position and + moves corresponding rook as well. DOES NOT change piece has_moved""" + # NEW_KING_POS = (2, 0), (6, 0), (2, 7), (6, 7) + corresponding_rook = {(2, 0): (0, 0), (6, 0): (7, 0), (2, 7): (0, 7), (6, 7): (7, 7)} + corresponding_rook_move = {(2, 0): (3, 0), (6, 0): (5, 0), (2, 7): (3, 7), (6, 7): (5, 7)} + rook_pos = corresponding_rook[new_king_position] + rook = self.board[rook_pos[0]][rook_pos[1]] + self.non_permanent_move(king, new_king_position) + self.non_permanent_move(rook, corresponding_rook_move[new_king_position]) + + def uncastle_king(self, king): + """Reverts a castle move""" + corresponding_rook = {(2, 0): (3, 0), (6, 0): (5, 0), (2, 7): (3, 7), (6, 7): (5, 7)} + corresponding_rook_move = {(2, 0): (0, 0), (6, 0): (7, 0), (2, 7): (0, 7), (6, 7): (7, 7)} + rook_pos = corresponding_rook[king.position] + rook = self.board[rook_pos[0]][rook_pos[1]] + self.non_permanent_move(rook, corresponding_rook_move[king.position]) + self.non_permanent_move(king, (4, king.position[1])) + + + def king_in_check(self, king, b): + """Returns if king is currently in check given board""" + # Check for bishop or queen in diagonal path of king + for m in king.get_possible_diagonal_moves(b): + if b[m[0]][m[1]] and b[m[0]][m[1]].name in ['Bishop', 'Queen']: + return True + + # Check for rook or queen in straight path of king + for m in king.get_possible_straight_line_moves(b): + if b[m[0]][m[1]] and b[m[0]][m[1]].name in ['Rook', 'Queen']: + return True + + # Check for opponent king next to current king + for m in king.get_possible_moves(b): + if b[m[0]][m[1]] and b[m[0]][m[1]].name == 'King': + return True + + # Check for opponent knights + for m in [(1, 2), (2, 1), (-1, 2), (-2, 1), (2, -1), (1, -2), (-1, -2), (-2, -1)]: + pos = king.position[0] + m[0], king.position[1] + m[1] + if pos[0] < 0 or pos[0] > 7 or pos[1] < 0 or pos[1] > 7: + continue + if b[pos[0]][pos[1]] and b[pos[0]][pos[1]].name == 'Knight' \ + and b[pos[0]][pos[1]].color != self.curr_player: + return True + + # Check for opponent pawns + y_dir = 1 if self.curr_player == 'w' else -1 + # Check diagonals + l_diag = king.position[0] - 1, king.position[1] + y_dir + r_diag = king.position[0] + 1, king.position[1] + y_dir + + if l_diag[0] >= 0: + if b[l_diag[0]][l_diag[1]] and b[l_diag[0]][l_diag[1]].name == 'Pawn' and b[l_diag[0]][l_diag[1]].color != self.curr_player: + return True + if r_diag[0] <= 7: + if b[r_diag[0]][r_diag[1]] and b[r_diag[0]][r_diag[1]].name == 'Pawn' and b[r_diag[0]][r_diag[1]].color != self.curr_player: + return True + + def is_curr_player_in_check(self, piece, moves): + """Returns list of valid moves that don't put player in check. """ + king = self.get_type_pieces_of_player('King', self.curr_player)[0] + b = self.board + piece_original_pos = piece.position + + poss_moves = [] + + for move in moves: + # Move piece to new move + piece_at_move_pos = self.board[move[0]][move[1]] + self.non_permanent_move(piece, move) + + if not self.king_in_check(king, b): + poss_moves.append(move) + + # Move piece back to original position + self.non_permanent_move(piece, piece_original_pos) + self.board[move[0]][move[1]] = piece_at_move_pos + + return poss_moves diff --git a/src/apps/pages/programs/Games/Chess/Game.py b/src/apps/pages/programs/Games/Chess/Game.py new file mode 100644 index 00000000..9fac9da8 --- /dev/null +++ b/src/apps/pages/programs/Games/Chess/Game.py @@ -0,0 +1,279 @@ +import pygame +from pygame.locals import * +import time +from pieces.Queen import Queen + +from ChessBoard import ChessBoard + + +class Game: + def __init__(self): + pygame.init() + self.game_display = pygame.display.set_mode((900, 650)) + pygame.display.set_caption('Chess') + + self.settings = {'board_image': 'images/orange_board.png'} + self.board_image = pygame.image.load(self.settings['board_image']) + + self.clock = pygame.time.Clock() + self.chess_board = ChessBoard() + + self.curr_selected_piece = None + self.curr_poss_moves = [] + self.all_poss_moves = self.get_all_poss_moves() + + self.white_pieces_taken_images = [] + self.black_pieces_taken_images = [] + + self.play_game() + + def play_game(self): + """Loop that executes the game""" + while True: + + # Draw whole window (and draw board) + self.draw_window() + + for event in pygame.event.get(): + if event.type == pygame.QUIT: + quit() + + if event.type == pygame.MOUSEBUTTONUP: + # Get user click + self.get_user_click() + + # pygame.display.flip() + self.clock.tick(60) + + def draw_window(self): + """Draws everything in the window""" + self.game_display.fill(white) + # Draw side menu + self.draw_side_menu() + # Draw bottom menu + # Draw board + self.draw_board() + pygame.display.update() + + def draw_side_menu(self): + """Draws right side menu""" + pygame.draw.rect(self.game_display, black, Rect((650, 100), (200, 400)), 5) + + # Draw box around current player + if self.chess_board.curr_player == 'b': + pygame.draw.rect(self.game_display, blue, Rect((700, 25), (100, 50)), 5) + else: + pygame.draw.rect(self.game_display, blue, Rect((700, 525), (100, 50)), 5) + + self.message_display('Black', (750, 50), fontsize=30) + self.message_display('White', (750, 550), fontsize=30) + + # Display all moves played + start = 0 + if len(self.get_all_played_moves()) > 10: + start = len(self.get_all_played_moves()) - 10 + for i, move in enumerate(self.get_all_played_moves()[start:]): + self.message_display(move, (740, 125 + (i * 30)), fontsize=20) + start += 1 + + # Display all black pieces taken + for i, image in enumerate(self.black_pieces_taken_images): + image = pygame.image.load(image) + image = pygame.transform.scale(image, (30, 30)) + pos = 610 + i * 20, 5 + self.game_display.blit(image, pos) + + # Display all white pieces taken + for i, image in enumerate(self.white_pieces_taken_images): + image = pygame.image.load(image) + image = pygame.transform.scale(image, (30, 30)) + pos = 610 + i * 20, 595 + self.game_display.blit(image, pos) + + def draw_board(self): + """Draw chess board and all pieces on the board""" + # Draw chess board + self.game_display.blit(self.board_image, (0, 0)) + + # Draw pieces on board + for piece in self.chess_board.get_all_pieces(): + image_position = piece.position + image_position = image_position[0] * 75, (7 - image_position[1]) * 75 + piece_image = pygame.image.load(piece.image) + self.game_display.blit(piece_image, image_position) + + # Determine if piece is currently selected + # If yes: + if self.curr_selected_piece: + # Highlight that piece + box_x, box_y = self.convert_space_to_coordinates(self.curr_selected_piece.position) + pygame.draw.rect(self.game_display, blue, Rect((box_x, box_y), (75, 75)), 5) + # Display possible moves for that piece + for move in self.curr_poss_moves: + box1_x, box1_y = self.convert_space_to_coordinates(move) + pygame.draw.rect(self.game_display, red, Rect((box1_x, box1_y), (75, 75)), 5) + + def get_user_click(self): + """Analyze the position clicked by the user.""" + x, y = pygame.mouse.get_pos() + # Determine if click is: + # On bottom menu + if y > 600: + pass + # On right side menu + elif x > 600: + pass + # If on board: + else: + # Convert coordinates into space + selected_space = self.convert_coordinates_to_space(x, y) + # If piece is not already selected: + if not self.curr_selected_piece: + + # Validate and set curr_selected_piece to this piece + if self.is_piece_of_curr_player(selected_space): + self.new_piece_selected(selected_space) + + # Else if piece already selected: + else: + # Determine if selected space is in possible moves + + # If space is current selected space + if selected_space == self.curr_selected_piece.position: + self.deselect_piece() + + # Else if space in possible moves: + elif selected_space in self.curr_poss_moves: + #### Check if piece is a king!!! ### + # Check if selected space is king and in poss_castle_move + if self.curr_selected_piece.name == 'King' and selected_space in self.chess_board.get_castle_moves_for_curr_player(): + # Castle that king + self.add_move(self.curr_selected_piece.position, selected_space) + self.chess_board.castle_king(self.curr_selected_piece, selected_space) + + else: + # Move selected piece to this spot + self.add_move(self.curr_selected_piece.position, selected_space) + self.move_piece(self.curr_selected_piece, selected_space) + + if self.curr_selected_piece.name == 'Pawn' and selected_space[1] == 0 or selected_space[1] == 7: + self.chess_board.board[selected_space[0]][selected_space[1]] = None + self.chess_board.board[selected_space[0]][selected_space[1]] = Queen(self.chess_board.curr_player, selected_space) + + # Deselect current piece and remove poss moves + self.deselect_piece() + # Change current player + self.change_curr_player() + + # Check for checkmate and get new list of all possible moves + self.all_poss_moves = self.get_all_poss_moves() + checkmate = True + for piece_pos in self.all_poss_moves: + if len(self.all_poss_moves[piece_pos]) != 0: + checkmate = False + if checkmate: + self.draw_window() + self.message_display('Checkmate!', (400, 300)) + winner = 'White' if self.chess_board.curr_player == 'b' else 'Black' + self.message_display('%s wins!' % winner, (400, 400)) + pygame.display.update() + time.sleep(2) + quit() + + # Else if another piece of curr player: + elif selected_space in [piece.position for piece in self.chess_board.get_curr_player_pieces()]: + # Make that piece current selected piece + self.new_piece_selected(selected_space) + + # Else (random non-selectable space): + else: + # Deselect current move + self.deselect_piece() + + def convert_coordinates_to_space(self, x, y): + """Converts (x, y) coordinates to corresponding space on board""" + # NOTE: Board is drawn upside down, so y axis is flipped + return x // 75, 7 - y // 75 + + def convert_space_to_coordinates(self, position): + """Returns the top left corner coordinate corresponding to given chess spot""" + return position[0] * 75, (7 - position[1]) * 75 + + def is_piece_of_curr_player(self, space): + """Returns if space holds a piece of current player""" + for piece in self.chess_board.get_curr_player_pieces(): + if space == piece.position: + return True + + def get_all_poss_moves(self): + """Returns dictionary of all possible moves available. NOTE: will return empty list if checkmate""" + # Creates dictionary of piece position to possible moves + moves = {} + pieces = self.chess_board.get_curr_player_pieces() + for piece in pieces: + p_moves = self.chess_board.get_poss_moves_for(piece) + moves[piece.position] = self.chess_board.is_curr_player_in_check(piece, p_moves) + return moves + + def get_curr_poss_moves(self): + """Returns possible moves corresponding to cuurently selected piece""" + return self.all_poss_moves[self.curr_selected_piece.position] + + def get_all_played_moves(self): + return self.chess_board.played_moves + + def move_piece(self, piece, new_position): + """Moves piece to new position and updates pieces taken""" + # NOTE: This just moves piece, does not check if move is valid + # Checks if piece is taken + piece_captured = self.chess_board.move_piece(piece, new_position) + if piece_captured: + self.piece_was_captured(piece_captured) + + def change_curr_player(self): + """Change current player between 'w' and 'b'""" + self.chess_board.curr_player = 'w' if self.chess_board.curr_player == 'b' else 'b' + + def new_piece_selected(self, new_space): + """Sets new space to curr_selected_piece and gets new moves for that piece""" + self.curr_selected_piece = self.chess_board.get_piece_at(new_space) + self.curr_poss_moves = self.get_curr_poss_moves() + + def deselect_piece(self): + """Deselects current piece""" + self.curr_selected_piece = None + self.curr_poss_moves = None + + def add_move(self, pos_1, pos_2): + """Add move to list of played moves""" + name = self.chess_board.curr_player.upper() + ': ' + move = name + self.convert_coordinate_to_space_name(pos_1) + ' -> ' + self.convert_coordinate_to_space_name(pos_2) + self.chess_board.played_moves.append(move) + + def convert_coordinate_to_space_name(self, coordinate): + """Returns converted name of position (ex: (1,3) -> 'B3')""" + conversions = {0 : 'A', 1: 'B', 2: 'C', 3: 'D', 4: 'E', 5: 'F', 6: 'G', 7: 'H'} + return str(conversions[coordinate[0]]) + str(coordinate[1] + 1) + + def piece_was_captured(self, piece): + """Updates list of pieces taken to display on side menu""" + if piece.color == 'w': + self.white_pieces_taken_images.append(piece.image) + else: + self.black_pieces_taken_images.append(piece.image) + + def message_display(self, text, point, fontsize=90): + """Displays message in window""" + large_text = pygame.font.Font('freesansbold.ttf', fontsize) + text_surface = large_text.render(text, True, black) + text_rect = text_surface.get_rect() + text_rect.center = (point) + self.game_display.blit(text_surface, text_rect) + +if __name__ == '__main__': + + white = (255,255,255) + blue = (34, 0, 255) + red = (209, 9, 9) + black = (0, 0, 0) + Game() diff --git a/src/apps/pages/programs/Games/Chess/README.md b/src/apps/pages/programs/Games/Chess/README.md new file mode 100644 index 00000000..a88ba0d9 --- /dev/null +++ b/src/apps/pages/programs/Games/Chess/README.md @@ -0,0 +1,21 @@ +# Pygame_Chess +Player v Player chess game made with Python 3.5 and Pygame + + + +To install and run: + +Download python3 from https://www.python.org/downloads/windows/ +Pip should be included in python3 download +Run: +``` +pip install pygame +``` +``` +git clone +``` + +cd into the folder it is downloaded and run +``` +python Game.py +``` diff --git a/src/apps/pages/programs/Games/Chess/__pycache__/ChessBoard.cpython-312.pyc b/src/apps/pages/programs/Games/Chess/__pycache__/ChessBoard.cpython-312.pyc new file mode 100644 index 00000000..2932566a Binary files /dev/null and b/src/apps/pages/programs/Games/Chess/__pycache__/ChessBoard.cpython-312.pyc differ diff --git a/src/apps/pages/programs/Games/Chess/__pycache__/ChessBoard.cpython-35.pyc b/src/apps/pages/programs/Games/Chess/__pycache__/ChessBoard.cpython-35.pyc new file mode 100644 index 00000000..5c202395 Binary files /dev/null and b/src/apps/pages/programs/Games/Chess/__pycache__/ChessBoard.cpython-35.pyc differ diff --git a/src/apps/pages/programs/Games/Chess/__pycache__/ChessBoard.cpython-36.pyc b/src/apps/pages/programs/Games/Chess/__pycache__/ChessBoard.cpython-36.pyc new file mode 100644 index 00000000..c25f9216 Binary files /dev/null and b/src/apps/pages/programs/Games/Chess/__pycache__/ChessBoard.cpython-36.pyc differ diff --git a/src/apps/pages/programs/Games/Chess/images/black_bishop.png b/src/apps/pages/programs/Games/Chess/images/black_bishop.png new file mode 100644 index 00000000..409a1cb0 Binary files /dev/null and b/src/apps/pages/programs/Games/Chess/images/black_bishop.png differ diff --git a/src/apps/pages/programs/Games/Chess/images/black_king.png b/src/apps/pages/programs/Games/Chess/images/black_king.png new file mode 100644 index 00000000..3b622522 Binary files /dev/null and b/src/apps/pages/programs/Games/Chess/images/black_king.png differ diff --git a/src/apps/pages/programs/Games/Chess/images/black_knight.png b/src/apps/pages/programs/Games/Chess/images/black_knight.png new file mode 100644 index 00000000..d8e011d5 Binary files /dev/null and b/src/apps/pages/programs/Games/Chess/images/black_knight.png differ diff --git a/src/apps/pages/programs/Games/Chess/images/black_pawn.png b/src/apps/pages/programs/Games/Chess/images/black_pawn.png new file mode 100644 index 00000000..cb114c6f Binary files /dev/null and b/src/apps/pages/programs/Games/Chess/images/black_pawn.png differ diff --git a/src/apps/pages/programs/Games/Chess/images/black_queen.png b/src/apps/pages/programs/Games/Chess/images/black_queen.png new file mode 100644 index 00000000..88b8d6f8 Binary files /dev/null and b/src/apps/pages/programs/Games/Chess/images/black_queen.png differ diff --git a/src/apps/pages/programs/Games/Chess/images/black_rook.png b/src/apps/pages/programs/Games/Chess/images/black_rook.png new file mode 100644 index 00000000..eb54cc6e Binary files /dev/null and b/src/apps/pages/programs/Games/Chess/images/black_rook.png differ diff --git a/src/apps/pages/programs/Games/Chess/images/blue_highlight_space.png b/src/apps/pages/programs/Games/Chess/images/blue_highlight_space.png new file mode 100644 index 00000000..e0fee6d5 Binary files /dev/null and b/src/apps/pages/programs/Games/Chess/images/blue_highlight_space.png differ diff --git a/src/apps/pages/programs/Games/Chess/images/board.png b/src/apps/pages/programs/Games/Chess/images/board.png new file mode 100644 index 00000000..e0428de0 Binary files /dev/null and b/src/apps/pages/programs/Games/Chess/images/board.png differ diff --git a/src/apps/pages/programs/Games/Chess/images/brown_chess_board.png b/src/apps/pages/programs/Games/Chess/images/brown_chess_board.png new file mode 100644 index 00000000..7f3cda24 Binary files /dev/null and b/src/apps/pages/programs/Games/Chess/images/brown_chess_board.png differ diff --git a/src/apps/pages/programs/Games/Chess/images/grass_board.png b/src/apps/pages/programs/Games/Chess/images/grass_board.png new file mode 100644 index 00000000..8839c8ef Binary files /dev/null and b/src/apps/pages/programs/Games/Chess/images/grass_board.png differ diff --git a/src/apps/pages/programs/Games/Chess/images/orange_board.png b/src/apps/pages/programs/Games/Chess/images/orange_board.png new file mode 100644 index 00000000..e0428de0 Binary files /dev/null and b/src/apps/pages/programs/Games/Chess/images/orange_board.png differ diff --git a/src/apps/pages/programs/Games/Chess/images/red_board.png b/src/apps/pages/programs/Games/Chess/images/red_board.png new file mode 100644 index 00000000..ec52f5a6 Binary files /dev/null and b/src/apps/pages/programs/Games/Chess/images/red_board.png differ diff --git a/src/apps/pages/programs/Games/Chess/images/red_highlight_space.png b/src/apps/pages/programs/Games/Chess/images/red_highlight_space.png new file mode 100644 index 00000000..6e012439 Binary files /dev/null and b/src/apps/pages/programs/Games/Chess/images/red_highlight_space.png differ diff --git a/src/apps/pages/programs/Games/Chess/images/white_bishop.png b/src/apps/pages/programs/Games/Chess/images/white_bishop.png new file mode 100644 index 00000000..b3de8638 Binary files /dev/null and b/src/apps/pages/programs/Games/Chess/images/white_bishop.png differ diff --git a/src/apps/pages/programs/Games/Chess/images/white_king.png b/src/apps/pages/programs/Games/Chess/images/white_king.png new file mode 100644 index 00000000..fc232b4e Binary files /dev/null and b/src/apps/pages/programs/Games/Chess/images/white_king.png differ diff --git a/src/apps/pages/programs/Games/Chess/images/white_knight.png b/src/apps/pages/programs/Games/Chess/images/white_knight.png new file mode 100644 index 00000000..9172fd3a Binary files /dev/null and b/src/apps/pages/programs/Games/Chess/images/white_knight.png differ diff --git a/src/apps/pages/programs/Games/Chess/images/white_pawn.png b/src/apps/pages/programs/Games/Chess/images/white_pawn.png new file mode 100644 index 00000000..4b6cf789 Binary files /dev/null and b/src/apps/pages/programs/Games/Chess/images/white_pawn.png differ diff --git a/src/apps/pages/programs/Games/Chess/images/white_queen.png b/src/apps/pages/programs/Games/Chess/images/white_queen.png new file mode 100644 index 00000000..7721bb6d Binary files /dev/null and b/src/apps/pages/programs/Games/Chess/images/white_queen.png differ diff --git a/src/apps/pages/programs/Games/Chess/images/white_rook.png b/src/apps/pages/programs/Games/Chess/images/white_rook.png new file mode 100644 index 00000000..ba522dfe Binary files /dev/null and b/src/apps/pages/programs/Games/Chess/images/white_rook.png differ diff --git a/src/apps/pages/programs/Games/Chess/pieces/Bishop.py b/src/apps/pages/programs/Games/Chess/pieces/Bishop.py new file mode 100644 index 00000000..3236cfdd --- /dev/null +++ b/src/apps/pages/programs/Games/Chess/pieces/Bishop.py @@ -0,0 +1,16 @@ +from pieces.Piece import Piece + + +class Bishop(Piece): + def __init__(self, color, position): + self.name = 'Bishop' + super(Bishop, self).__init__(color, position) + if self.color == 'w': + self.image = 'images/white_bishop.png' + else: + self.image = 'images/black_bishop.png' + + self.value = 3 + + def get_possible_moves(self, board): + return self.get_possible_diagonal_moves(board) \ No newline at end of file diff --git a/src/apps/pages/programs/Games/Chess/pieces/King.py b/src/apps/pages/programs/Games/Chess/pieces/King.py new file mode 100644 index 00000000..c5b67c95 --- /dev/null +++ b/src/apps/pages/programs/Games/Chess/pieces/King.py @@ -0,0 +1,29 @@ +from pieces.Piece import Piece + + +class King(Piece): + def __init__(self, color, position): + self.name = 'King' + super(King, self).__init__(color, position) + if self.color == 'w': + self.image = 'images/white_king.png' + else: + self.image = 'images/black_king.png' + + self.value = 100 + + def get_possible_moves(self, board): + moves = [] + for i in range(-1, 2): + for e in range(-1, 2): + space = self.position[0] + e, self.position[1] + i + if space[0] < 0 or space[0] > 7 or space[1] < 0 or space[1] > 7: + continue + piece = board[space[0]][space[1]] + if not piece or self.is_opponent(piece): + moves.append(space) + + return moves + + def is_opponent(self, piece): + return piece.color == self.opponent_color diff --git a/src/apps/pages/programs/Games/Chess/pieces/Knight.py b/src/apps/pages/programs/Games/Chess/pieces/Knight.py new file mode 100644 index 00000000..2c4e6b8c --- /dev/null +++ b/src/apps/pages/programs/Games/Chess/pieces/Knight.py @@ -0,0 +1,25 @@ +from pieces.Piece import Piece + + +class Knight(Piece): + def __init__(self, color, position): + self.name = 'Knight' + super(Knight, self).__init__(color, position) + if self.color == 'w': + self.image = 'images/white_knight.png' + else: + self.image = 'images/black_knight.png' + + self.value = 3 + + def get_possible_moves(self, board): + poss_moves = [(1, 2), (2, 1), (-1, 2), (-2, 1), (2, -1), (1, -2), (-1, -2), (-2, -1)] + moves = [] + for move in poss_moves: + pos = self.position[0] + move[0], self.position[1] + move[1] + if pos[0] < 0 or pos[0] > 7 or pos[1] < 0 or pos[1] > 7: + continue + piece = board[pos[0]][pos[1]] + if not piece or self.is_opponent(piece): + moves.append(pos) + return moves \ No newline at end of file diff --git a/src/apps/pages/programs/Games/Chess/pieces/Pawn.py b/src/apps/pages/programs/Games/Chess/pieces/Pawn.py new file mode 100644 index 00000000..4d21dcf4 --- /dev/null +++ b/src/apps/pages/programs/Games/Chess/pieces/Pawn.py @@ -0,0 +1,43 @@ +from pieces.Piece import Piece + + +class Pawn(Piece): + def __init__(self, color, position): + self.name = 'Pawn' + super(Pawn, self).__init__(color, position) + if self.color == 'w': + self.image = 'images/white_pawn.png' + else: + self.image = 'images/black_pawn.png' + + self.value = 1 + + def get_possible_moves(self, board): + moves = [] + + if not self.is_piece_in_front(board): + moves.append((self.position[0], self.position[1] + self.direction)) + + if (not self.has_moved) and (not board[self.position[0]][self.position[1] + 2 * self.direction]): + moves.append((self.position[0], self.position[1] + 2 * self.direction)) + + if self.position[0] < 7: + right_diagonal = board[self.position[0] + 1][self.position[1] + self.direction] + if right_diagonal and self.is_opponent(right_diagonal): + moves.append(right_diagonal.position) + + if self.position[0] > 0: + left_diagonal = board[self.position[0] - 1][self.position[1] + self.direction] + if left_diagonal and self.is_opponent(left_diagonal): + moves.append(left_diagonal.position) + + return moves + + def is_piece_in_front(self, board): + return board[self.position[0]][self.position[1] + self.direction] + + def is_opponent_piece_diagonal(self, board, left_side): + side = -1 if left_side else 1 + return board[self.position[0] + side][self.position[1] + self.direction].color == self.opponent_color + + diff --git a/src/apps/pages/programs/Games/Chess/pieces/Piece.py b/src/apps/pages/programs/Games/Chess/pieces/Piece.py new file mode 100644 index 00000000..36f20040 --- /dev/null +++ b/src/apps/pages/programs/Games/Chess/pieces/Piece.py @@ -0,0 +1,138 @@ +class Piece: + def __init__(self, color, position): + self.name + self.position = position + self.color = color.lower() + self.opponent_color = 'b' if self.color == 'w' else 'w' + if color not in ['b', 'w']: + raise TypeError('%s color should be \'w\' or \'b\'' % self.name) + + self.direction = 1 if self.color == 'w' else -1 + self.has_moved = False + self.turn_first_moved = 0 + + def get_possible_moves(self, board): + return [] + + def can_move(self, move, board): + return move in self.get_possible_moves(board) + + def move(self, move): + self.position = move + + def is_opponent(self, piece): + return piece.color == self.opponent_color + + def get_possible_straight_line_moves(self, board): + # Does not affect anything. Returns list of moves + moves = [] + curr_pos = self.position[0], self.position[1] + 1 + while curr_pos[1] <= 7: + piece = board[curr_pos[0]][curr_pos[1]] + if not piece: + moves.append(curr_pos) + elif self.is_opponent(piece): + moves.append(curr_pos) + break + else: + break + + curr_pos = curr_pos[0], curr_pos[1] + 1 + + curr_pos = self.position[0], self.position[1] - 1 + while curr_pos[1] >= 0: + piece = board[curr_pos[0]][curr_pos[1]] + if not piece: + moves.append(curr_pos) + elif self.is_opponent(piece): + moves.append(curr_pos) + break + else: + break + + curr_pos = curr_pos[0], curr_pos[1] - 1 + + curr_pos = self.position[0] + 1, self.position[1] + while curr_pos[0] <= 7: + piece = board[curr_pos[0]][curr_pos[1]] + if not piece: + moves.append(curr_pos) + elif self.is_opponent(piece): + moves.append(curr_pos) + break + else: + break + + curr_pos = curr_pos[0] + 1, curr_pos[1] + + curr_pos = self.position[0] - 1, self.position[1] + while curr_pos[0] >= 0: + piece = board[curr_pos[0]][curr_pos[1]] + if not piece: + moves.append(curr_pos) + elif self.is_opponent(piece): + moves.append(curr_pos) + break + else: + break + + curr_pos = curr_pos[0] - 1, curr_pos[1] + + return moves + + def get_possible_diagonal_moves(self, board): + # Does not affect anything. Returns list of moves + moves = [] + curr_pos = self.position[0] + 1, self.position[1] + 1 + while curr_pos[1] <= 7 and curr_pos[0] <= 7: + piece = board[curr_pos[0]][curr_pos[1]] + if not piece: + moves.append(curr_pos) + elif self.is_opponent(piece): + moves.append(curr_pos) + break + else: + break + + curr_pos = curr_pos[0] + 1, curr_pos[1] + 1 + + curr_pos = self.position[0] + 1, self.position[1] - 1 + while curr_pos[1] >= 0 and curr_pos[0] <= 7: + piece = board[curr_pos[0]][curr_pos[1]] + if not piece: + moves.append(curr_pos) + elif self.is_opponent(piece): + moves.append(curr_pos) + break + else: + break + + curr_pos = curr_pos[0] + 1, curr_pos[1] - 1 + + curr_pos = self.position[0] - 1, self.position[1] + 1 + while curr_pos[0] >= 0 and curr_pos[1] <= 7: + piece = board[curr_pos[0]][curr_pos[1]] + if not piece: + moves.append(curr_pos) + elif self.is_opponent(piece): + moves.append(curr_pos) + break + else: + break + + curr_pos = curr_pos[0] - 1, curr_pos[1] + 1 + + curr_pos = self.position[0] - 1, self.position[1] - 1 + while curr_pos[1] >= 0 and curr_pos[0] >= 0: + piece = board[curr_pos[0]][curr_pos[1]] + if not piece: + moves.append(curr_pos) + elif self.is_opponent(piece): + moves.append(curr_pos) + break + else: + break + + curr_pos = curr_pos[0] - 1, curr_pos[1] - 1 + + return moves \ No newline at end of file diff --git a/src/apps/pages/programs/Games/Chess/pieces/Queen.py b/src/apps/pages/programs/Games/Chess/pieces/Queen.py new file mode 100644 index 00000000..9aa13aba --- /dev/null +++ b/src/apps/pages/programs/Games/Chess/pieces/Queen.py @@ -0,0 +1,16 @@ +from pieces.Piece import Piece + + +class Queen(Piece): + def __init__(self, color, position): + self.name = 'Queen' + super(Queen, self).__init__(color, position) + if self.color == 'w': + self.image = 'images/white_queen.png' + else: + self.image = 'images/black_queen.png' + + self.value = 9 + + def get_possible_moves(self, board): + return self.get_possible_straight_line_moves(board) + self.get_possible_diagonal_moves(board) diff --git a/src/apps/pages/programs/Games/Chess/pieces/Rook.py b/src/apps/pages/programs/Games/Chess/pieces/Rook.py new file mode 100644 index 00000000..fd345f74 --- /dev/null +++ b/src/apps/pages/programs/Games/Chess/pieces/Rook.py @@ -0,0 +1,17 @@ +from pieces.Piece import Piece + + +class Rook(Piece): + def __init__(self, color, position): + self.name = 'Rook' + super(Rook, self).__init__(color, position) + if self.color == 'w': + self.image = 'images/white_rook.png' + else: + self.image = 'images/black_rook.png' + + self.value = 5 + + def get_possible_moves(self, board): + return self.get_possible_straight_line_moves(board) + diff --git a/src/apps/pages/programs/Games/Chess/pieces/__pycache__/Bishop.cpython-312.pyc b/src/apps/pages/programs/Games/Chess/pieces/__pycache__/Bishop.cpython-312.pyc new file mode 100644 index 00000000..4cfc84a2 Binary files /dev/null and b/src/apps/pages/programs/Games/Chess/pieces/__pycache__/Bishop.cpython-312.pyc differ diff --git a/src/apps/pages/programs/Games/Chess/pieces/__pycache__/Bishop.cpython-35.pyc b/src/apps/pages/programs/Games/Chess/pieces/__pycache__/Bishop.cpython-35.pyc new file mode 100644 index 00000000..ed64e570 Binary files /dev/null and b/src/apps/pages/programs/Games/Chess/pieces/__pycache__/Bishop.cpython-35.pyc differ diff --git a/src/apps/pages/programs/Games/Chess/pieces/__pycache__/Bishop.cpython-36.pyc b/src/apps/pages/programs/Games/Chess/pieces/__pycache__/Bishop.cpython-36.pyc new file mode 100644 index 00000000..ea6f3c30 Binary files /dev/null and b/src/apps/pages/programs/Games/Chess/pieces/__pycache__/Bishop.cpython-36.pyc differ diff --git a/src/apps/pages/programs/Games/Chess/pieces/__pycache__/King.cpython-312.pyc b/src/apps/pages/programs/Games/Chess/pieces/__pycache__/King.cpython-312.pyc new file mode 100644 index 00000000..fd60ce4d Binary files /dev/null and b/src/apps/pages/programs/Games/Chess/pieces/__pycache__/King.cpython-312.pyc differ diff --git a/src/apps/pages/programs/Games/Chess/pieces/__pycache__/King.cpython-35.pyc b/src/apps/pages/programs/Games/Chess/pieces/__pycache__/King.cpython-35.pyc new file mode 100644 index 00000000..400e394e Binary files /dev/null and b/src/apps/pages/programs/Games/Chess/pieces/__pycache__/King.cpython-35.pyc differ diff --git a/src/apps/pages/programs/Games/Chess/pieces/__pycache__/King.cpython-36.pyc b/src/apps/pages/programs/Games/Chess/pieces/__pycache__/King.cpython-36.pyc new file mode 100644 index 00000000..efdd3819 Binary files /dev/null and b/src/apps/pages/programs/Games/Chess/pieces/__pycache__/King.cpython-36.pyc differ diff --git a/src/apps/pages/programs/Games/Chess/pieces/__pycache__/Knight.cpython-312.pyc b/src/apps/pages/programs/Games/Chess/pieces/__pycache__/Knight.cpython-312.pyc new file mode 100644 index 00000000..274a8277 Binary files /dev/null and b/src/apps/pages/programs/Games/Chess/pieces/__pycache__/Knight.cpython-312.pyc differ diff --git a/src/apps/pages/programs/Games/Chess/pieces/__pycache__/Knight.cpython-35.pyc b/src/apps/pages/programs/Games/Chess/pieces/__pycache__/Knight.cpython-35.pyc new file mode 100644 index 00000000..6c42fe2d Binary files /dev/null and b/src/apps/pages/programs/Games/Chess/pieces/__pycache__/Knight.cpython-35.pyc differ diff --git a/src/apps/pages/programs/Games/Chess/pieces/__pycache__/Knight.cpython-36.pyc b/src/apps/pages/programs/Games/Chess/pieces/__pycache__/Knight.cpython-36.pyc new file mode 100644 index 00000000..a0fba164 Binary files /dev/null and b/src/apps/pages/programs/Games/Chess/pieces/__pycache__/Knight.cpython-36.pyc differ diff --git a/src/apps/pages/programs/Games/Chess/pieces/__pycache__/Pawn.cpython-312.pyc b/src/apps/pages/programs/Games/Chess/pieces/__pycache__/Pawn.cpython-312.pyc new file mode 100644 index 00000000..60c89fac Binary files /dev/null and b/src/apps/pages/programs/Games/Chess/pieces/__pycache__/Pawn.cpython-312.pyc differ diff --git a/src/apps/pages/programs/Games/Chess/pieces/__pycache__/Pawn.cpython-35.pyc b/src/apps/pages/programs/Games/Chess/pieces/__pycache__/Pawn.cpython-35.pyc new file mode 100644 index 00000000..be85bf6a Binary files /dev/null and b/src/apps/pages/programs/Games/Chess/pieces/__pycache__/Pawn.cpython-35.pyc differ diff --git a/src/apps/pages/programs/Games/Chess/pieces/__pycache__/Pawn.cpython-36.pyc b/src/apps/pages/programs/Games/Chess/pieces/__pycache__/Pawn.cpython-36.pyc new file mode 100644 index 00000000..f71ea750 Binary files /dev/null and b/src/apps/pages/programs/Games/Chess/pieces/__pycache__/Pawn.cpython-36.pyc differ diff --git a/src/apps/pages/programs/Games/Chess/pieces/__pycache__/Piece.cpython-312.pyc b/src/apps/pages/programs/Games/Chess/pieces/__pycache__/Piece.cpython-312.pyc new file mode 100644 index 00000000..7ec8fa3f Binary files /dev/null and b/src/apps/pages/programs/Games/Chess/pieces/__pycache__/Piece.cpython-312.pyc differ diff --git a/src/apps/pages/programs/Games/Chess/pieces/__pycache__/Piece.cpython-35.pyc b/src/apps/pages/programs/Games/Chess/pieces/__pycache__/Piece.cpython-35.pyc new file mode 100644 index 00000000..fc6e6974 Binary files /dev/null and b/src/apps/pages/programs/Games/Chess/pieces/__pycache__/Piece.cpython-35.pyc differ diff --git a/src/apps/pages/programs/Games/Chess/pieces/__pycache__/Piece.cpython-36.pyc b/src/apps/pages/programs/Games/Chess/pieces/__pycache__/Piece.cpython-36.pyc new file mode 100644 index 00000000..65f2d07d Binary files /dev/null and b/src/apps/pages/programs/Games/Chess/pieces/__pycache__/Piece.cpython-36.pyc differ diff --git a/src/apps/pages/programs/Games/Chess/pieces/__pycache__/Queen.cpython-312.pyc b/src/apps/pages/programs/Games/Chess/pieces/__pycache__/Queen.cpython-312.pyc new file mode 100644 index 00000000..1458c278 Binary files /dev/null and b/src/apps/pages/programs/Games/Chess/pieces/__pycache__/Queen.cpython-312.pyc differ diff --git a/src/apps/pages/programs/Games/Chess/pieces/__pycache__/Queen.cpython-35.pyc b/src/apps/pages/programs/Games/Chess/pieces/__pycache__/Queen.cpython-35.pyc new file mode 100644 index 00000000..78c67382 Binary files /dev/null and b/src/apps/pages/programs/Games/Chess/pieces/__pycache__/Queen.cpython-35.pyc differ diff --git a/src/apps/pages/programs/Games/Chess/pieces/__pycache__/Queen.cpython-36.pyc b/src/apps/pages/programs/Games/Chess/pieces/__pycache__/Queen.cpython-36.pyc new file mode 100644 index 00000000..4f74c083 Binary files /dev/null and b/src/apps/pages/programs/Games/Chess/pieces/__pycache__/Queen.cpython-36.pyc differ diff --git a/src/apps/pages/programs/Games/Chess/pieces/__pycache__/Rook.cpython-312.pyc b/src/apps/pages/programs/Games/Chess/pieces/__pycache__/Rook.cpython-312.pyc new file mode 100644 index 00000000..f8e406b2 Binary files /dev/null and b/src/apps/pages/programs/Games/Chess/pieces/__pycache__/Rook.cpython-312.pyc differ diff --git a/src/apps/pages/programs/Games/Chess/pieces/__pycache__/Rook.cpython-35.pyc b/src/apps/pages/programs/Games/Chess/pieces/__pycache__/Rook.cpython-35.pyc new file mode 100644 index 00000000..ccbcb2fe Binary files /dev/null and b/src/apps/pages/programs/Games/Chess/pieces/__pycache__/Rook.cpython-35.pyc differ diff --git a/src/apps/pages/programs/Games/Chess/pieces/__pycache__/Rook.cpython-36.pyc b/src/apps/pages/programs/Games/Chess/pieces/__pycache__/Rook.cpython-36.pyc new file mode 100644 index 00000000..f5e7a950 Binary files /dev/null and b/src/apps/pages/programs/Games/Chess/pieces/__pycache__/Rook.cpython-36.pyc differ