Learn how to create a fully functional chess game in Python using the Pygame library. Follow this step-by-step tutorial for game development enthusiasts.
Are you ready to embark on a journey into the captivating world of chess programming? Look no further! In this Pygame tutorial, we will dive headfirst into the realm of Python-powered chess games, helping you create a masterpiece that will leave enthusiasts in awe.
Table of Contents
- Introduction
- Getting Started with Python Chess Game Tutorial with Pygame
- Python Chess Game Tutorial with Pygame
- Full Source Code
- Explanation of Source Code
- Conclusion
- FAQs
1. Introduction
Welcome to the Python Chess Game Tutorial with Pygame! Chess is a timeless game that has captured the hearts and minds of players for centuries. If you've ever wondered how to develop your own chess game and bring it to life, you're in the right place. In this comprehensive tutorial, we will guide you through the entire process, from setting up your development environment to building a fully functional chess game using Python and Pygame.
So, let's embark on this exciting journey and explore the world of chess game development. Whether you're a beginner looking to learn Python or an experienced programmer eager to delve into game development, this tutorial has something for everyone.
Getting Started with Python Chess Game Tutorial with Pygame
2. Setting up Your Development Environment
Before we dive into the world of Python chess game development, let's ensure you have everything you need to get started.
- Install Python: If you haven't already, download and install Python from the official website. Make sure to choose the latest stable version.
- Pygame Installation: Pygame is a powerful library that simplifies game development. You can install it using pip by running the following command in your terminal or command prompt:
pip install pygame
- Code Editor: Choose a code editor that suits your preferences. Popular options include Visual Studio Code, PyCharm, and Jupyter Notebook.
Now that your environment is set up, let's move on to creating our Python chess game.
3. Python Chess Game Tutorial with Pygame
Initializing the Chessboard
In this section, we'll start building the chessboard. We'll create a graphical interface using Pygame and set up the initial chessboard layout.
To kick things off, we'll import the necessary libraries:
import pygame
Next, we'll initialize Pygame and set up the display window:
pygame.init() screen = pygame.display.set_mode((800, 600)) pygame.display.set_caption("Python Chess Game Tutorial with Pygame")
4. Full Source Code
# Importing Modules import pygame # Initialising pygame module pygame.init() # Setting Width and height of the Chess Game screen WIDTH = 800 HEIGHT = 800 screen = pygame.display.set_mode([WIDTH, HEIGHT]) pygame.display.set_caption('Two-Player Chess Game') font = pygame.font.Font('freesansbold.ttf', 20) medium_font = pygame.font.Font('freesansbold.ttf', 40) big_font = pygame.font.Font('freesansbold.ttf', 50) timer = pygame.time.Clock() fps = 60 # game variables and images white_pieces = ['rook', 'knight', 'bishop', 'king', 'queen', 'bishop', 'knight', 'rook', 'pawn', 'pawn', 'pawn', 'pawn', 'pawn', 'pawn', 'pawn', 'pawn'] white_locations = [(0, 0), (1, 0), (2, 0), (3, 0), (4, 0), (5, 0), (6, 0), (7, 0), (0, 1), (1, 1), (2, 1), (3, 1), (4, 1), (5, 1), (6, 1), (7, 1)] black_pieces = ['rook', 'knight', 'bishop', 'king', 'queen', 'bishop', 'knight', 'rook', 'pawn', 'pawn', 'pawn', 'pawn', 'pawn', 'pawn', 'pawn', 'pawn'] black_locations = [(0, 7), (1, 7), (2, 7), (3, 7), (4, 7), (5, 7), (6, 7), (7, 7), (0, 6), (1, 6), (2, 6), (3, 6), (4, 6), (5, 6), (6, 6), (7, 6)] captured_pieces_white = [] captured_pieces_black = [] # 0 - whites turn no selection: 1-whites turn piece selected: 2- black turn no selection, 3 - black turn piece selected turn_step = 0 selection = 100 valid_moves = [] # load in game piece images (queen, king, rook, bishop, knight, pawn) x 2 black_queen = pygame.image.load('./images/black queen.png') black_queen = pygame.transform.scale(black_queen, (80, 80)) black_queen_small = pygame.transform.scale(black_queen, (45, 45)) black_king = pygame.image.load('./images/black king.png') black_king = pygame.transform.scale(black_king, (80, 80)) black_king_small = pygame.transform.scale(black_king, (45, 45)) black_rook = pygame.image.load('./images/black rook.png') black_rook = pygame.transform.scale(black_rook, (80, 80)) black_rook_small = pygame.transform.scale(black_rook, (45, 45)) black_bishop = pygame.image.load('./images/black bishop.png') black_bishop = pygame.transform.scale(black_bishop, (80, 80)) black_bishop_small = pygame.transform.scale(black_bishop, (45, 45)) black_knight = pygame.image.load('./images/black knight.png') black_knight = pygame.transform.scale(black_knight, (80, 80)) black_knight_small = pygame.transform.scale(black_knight, (45, 45)) black_pawn = pygame.image.load('./images/black pawn.png') black_pawn = pygame.transform.scale(black_pawn, (65, 65)) black_pawn_small = pygame.transform.scale(black_pawn, (45, 45)) white_queen = pygame.image.load('./images/white queen.png') white_queen = pygame.transform.scale(white_queen, (80, 80)) white_queen_small = pygame.transform.scale(white_queen, (45, 45)) white_king = pygame.image.load('./images/white king.png') white_king = pygame.transform.scale(white_king, (80, 80)) white_king_small = pygame.transform.scale(white_king, (45, 45)) white_rook = pygame.image.load('./images/white rook.png') white_rook = pygame.transform.scale(white_rook, (80, 80)) white_rook_small = pygame.transform.scale(white_rook, (45, 45)) white_bishop = pygame.image.load('./images/white bishop.png') white_bishop = pygame.transform.scale(white_bishop, (80, 80)) white_bishop_small = pygame.transform.scale(white_bishop, (45, 45)) white_knight = pygame.image.load('./images/white knight.png') white_knight = pygame.transform.scale(white_knight, (80, 80)) white_knight_small = pygame.transform.scale(white_knight, (45, 45)) white_pawn = pygame.image.load('./images/white pawn.png') white_pawn = pygame.transform.scale(white_pawn, (65, 65)) white_pawn_small = pygame.transform.scale(white_pawn, (45, 45)) white_images = [white_pawn, white_queen, white_king, white_knight, white_rook, white_bishop] small_white_images = [white_pawn_small, white_queen_small, white_king_small, white_knight_small, white_rook_small, white_bishop_small] black_images = [black_pawn, black_queen, black_king, black_knight, black_rook, black_bishop] small_black_images = [black_pawn_small, black_queen_small, black_king_small, black_knight_small, black_rook_small, black_bishop_small] piece_list = ['pawn', 'queen', 'king', 'knight', 'rook', 'bishop'] # check variables/ flashing counter counter = 0 winner = '' game_over = False # draw main game board def draw_board(): for i in range(32): column = i % 4 row = i // 4 if row % 2 == 0: pygame.draw.rect(screen, 'light gray', [ 600 - (column * 200), row * 100, 100, 100]) else: pygame.draw.rect(screen, 'light gray', [ 700 - (column * 200), row * 100, 100, 100]) pygame.draw.rect(screen, 'gray', [0, 800, WIDTH, 100]) pygame.draw.rect(screen, 'gold', [0, 800, WIDTH, 100], 5) pygame.draw.rect(screen, 'gold', [800, 0, 200, HEIGHT], 5) status_text = ['White: Select a Piece to Move!', 'White: Select a Destination!', 'Black: Select a Piece to Move!', 'Black: Select a Destination!'] screen.blit(big_font.render( status_text[turn_step], True, 'black'), (20, 820)) for i in range(9): pygame.draw.line(screen, 'black', (0, 100 * i), (800, 100 * i), 2) pygame.draw.line(screen, 'black', (100 * i, 0), (100 * i, 800), 2) screen.blit(medium_font.render('FORFEIT', True, 'black'), (810, 830)) # draw pieces onto board def draw_pieces(): for i in range(len(white_pieces)): index = piece_list.index(white_pieces[i]) if white_pieces[i] == 'pawn': screen.blit( white_pawn, (white_locations[i][0] * 100 + 22, white_locations[i][1] * 100 + 30)) else: screen.blit(white_images[index], (white_locations[i] [0] * 100 + 10, white_locations[i][1] * 100 + 10)) if turn_step < 2: if selection == i: pygame.draw.rect(screen, 'red', [white_locations[i][0] * 100 + 1, white_locations[i][1] * 100 + 1, 100, 100], 2) for i in range(len(black_pieces)): index = piece_list.index(black_pieces[i]) if black_pieces[i] == 'pawn': screen.blit( black_pawn, (black_locations[i][0] * 100 + 22, black_locations[i][1] * 100 + 30)) else: screen.blit(black_images[index], (black_locations[i] [0] * 100 + 10, black_locations[i][1] * 100 + 10)) if turn_step >= 2: if selection == i: pygame.draw.rect(screen, 'blue', [black_locations[i][0] * 100 + 1, black_locations[i][1] * 100 + 1, 100, 100], 2) # function to check all pieces valid options on board def check_options(pieces, locations, turn): moves_list = [] all_moves_list = [] for i in range((len(pieces))): location = locations[i] piece = pieces[i] if piece == 'pawn': moves_list = check_pawn(location, turn) elif piece == 'rook': moves_list = check_rook(location, turn) elif piece == 'knight': moves_list = check_knight(location, turn) elif piece == 'bishop': moves_list = check_bishop(location, turn) elif piece == 'queen': moves_list = check_queen(location, turn) elif piece == 'king': moves_list = check_king(location, turn) all_moves_list.append(moves_list) return all_moves_list # check king valid moves def check_king(position, color): moves_list = [] if color == 'white': enemies_list = black_locations friends_list = white_locations else: friends_list = black_locations enemies_list = white_locations # 8 squares to check for kings, they can go one square any direction targets = [(1, 0), (1, 1), (1, -1), (-1, 0), (-1, 1), (-1, -1), (0, 1), (0, -1)] for i in range(8): target = (position[0] + targets[i][0], position[1] + targets[i][1]) if target not in friends_list and 0 <= target[0] <= 7 and 0 <= target[1] <= 7: moves_list.append(target) return moves_list # check queen valid moves def check_queen(position, color): moves_list = check_bishop(position, color) second_list = check_rook(position, color) for i in range(len(second_list)): moves_list.append(second_list[i]) return moves_list # check bishop moves def check_bishop(position, color): moves_list = [] if color == 'white': enemies_list = black_locations friends_list = white_locations else: friends_list = black_locations enemies_list = white_locations for i in range(4): # up-right, up-left, down-right, down-left path = True chain = 1 if i == 0: x = 1 y = -1 elif i == 1: x = -1 y = -1 elif i == 2: x = 1 y = 1 else: x = -1 y = 1 while path: if (position[0] + (chain * x), position[1] + (chain * y)) not in friends_list and \ 0 <= position[0] + (chain * x) <= 7 and 0 <= position[1] + (chain * y) <= 7: moves_list.append( (position[0] + (chain * x), position[1] + (chain * y))) if (position[0] + (chain * x), position[1] + (chain * y)) in enemies_list: path = False chain += 1 else: path = False return moves_list # check rook moves def check_rook(position, color): moves_list = [] if color == 'white': enemies_list = black_locations friends_list = white_locations else: friends_list = black_locations enemies_list = white_locations for i in range(4): # down, up, right, left path = True chain = 1 if i == 0: x = 0 y = 1 elif i == 1: x = 0 y = -1 elif i == 2: x = 1 y = 0 else: x = -1 y = 0 while path: if (position[0] + (chain * x), position[1] + (chain * y)) not in friends_list and \ 0 <= position[0] + (chain * x) <= 7 and 0 <= position[1] + (chain * y) <= 7: moves_list.append( (position[0] + (chain * x), position[1] + (chain * y))) if (position[0] + (chain * x), position[1] + (chain * y)) in enemies_list: path = False chain += 1 else: path = False return moves_list # check valid pawn moves def check_pawn(position, color): moves_list = [] if color == 'white': if (position[0], position[1] + 1) not in white_locations and \ (position[0], position[1] + 1) not in black_locations and position[1] < 7: moves_list.append((position[0], position[1] + 1)) if (position[0], position[1] + 2) not in white_locations and \ (position[0], position[1] + 2) not in black_locations and position[1] == 1: moves_list.append((position[0], position[1] + 2)) if (position[0] + 1, position[1] + 1) in black_locations: moves_list.append((position[0] + 1, position[1] + 1)) if (position[0] - 1, position[1] + 1) in black_locations: moves_list.append((position[0] - 1, position[1] + 1)) else: if (position[0], position[1] - 1) not in white_locations and \ (position[0], position[1] - 1) not in black_locations and position[1] > 0: moves_list.append((position[0], position[1] - 1)) if (position[0], position[1] - 2) not in white_locations and \ (position[0], position[1] - 2) not in black_locations and position[1] == 6: moves_list.append((position[0], position[1] - 2)) if (position[0] + 1, position[1] - 1) in white_locations: moves_list.append((position[0] + 1, position[1] - 1)) if (position[0] - 1, position[1] - 1) in white_locations: moves_list.append((position[0] - 1, position[1] - 1)) return moves_list # check valid knight moves def check_knight(position, color): moves_list = [] if color == 'white': enemies_list = black_locations friends_list = white_locations else: friends_list = black_locations enemies_list = white_locations # 8 squares to check for knights, they can go two squares in one direction and one in another targets = [(1, 2), (1, -2), (2, 1), (2, -1), (-1, 2), (-1, -2), (-2, 1), (-2, -1)] for i in range(8): target = (position[0] + targets[i][0], position[1] + targets[i][1]) if target not in friends_list and 0 <= target[0] <= 7 and 0 <= target[1] <= 7: moves_list.append(target) return moves_list # check for valid moves for just selected piece def check_valid_moves(): if turn_step < 2: options_list = white_options else: options_list = black_options valid_options = options_list[selection] return valid_options # draw valid moves on screen def draw_valid(moves): if turn_step < 2: color = 'red' else: color = 'blue' for i in range(len(moves)): pygame.draw.circle( screen, color, (moves[i][0] * 100 + 50, moves[i][1] * 100 + 50), 5) # draw captured pieces on side of screen def draw_captured(): for i in range(len(captured_pieces_white)): captured_piece = captured_pieces_white[i] index = piece_list.index(captured_piece) screen.blit(small_black_images[index], (825, 5 + 50 * i)) for i in range(len(captured_pieces_black)): captured_piece = captured_pieces_black[i] index = piece_list.index(captured_piece) screen.blit(small_white_images[index], (925, 5 + 50 * i)) # draw a flashing square around king if in check def draw_check(): if turn_step < 2: if 'king' in white_pieces: king_index = white_pieces.index('king') king_location = white_locations[king_index] for i in range(len(black_options)): if king_location in black_options[i]: if counter < 15: pygame.draw.rect(screen, 'dark red', [white_locations[king_index][0] * 100 + 1, white_locations[king_index][1] * 100 + 1, 100, 100], 5) else: if 'king' in black_pieces: king_index = black_pieces.index('king') king_location = black_locations[king_index] for i in range(len(white_options)): if king_location in white_options[i]: if counter < 15: pygame.draw.rect(screen, 'dark blue', [black_locations[king_index][0] * 100 + 1, black_locations[king_index][1] * 100 + 1, 100, 100], 5) def draw_game_over(): pygame.draw.rect(screen, 'black', [200, 200, 400, 70]) screen.blit(font.render( f'{winner} won the game!', True, 'white'), (210, 210)) screen.blit(font.render(f'Press ENTER to Restart!', True, 'white'), (210, 240)) # main game loop black_options = check_options(black_pieces, black_locations, 'black') white_options = check_options(white_pieces, white_locations, 'white') run = True while run: timer.tick(fps) if counter < 30: counter += 1 else: counter = 0 screen.fill('dark gray') draw_board() draw_pieces() draw_captured() draw_check() if selection != 100: valid_moves = check_valid_moves() draw_valid(valid_moves) # event handling for event in pygame.event.get(): if event.type == pygame.QUIT: run = False if event.type == pygame.MOUSEBUTTONDOWN and event.button == 1 and not game_over: x_coord = event.pos[0] // 100 y_coord = event.pos[1] // 100 click_coords = (x_coord, y_coord) if turn_step <= 1: if click_coords == (8, 8) or click_coords == (9, 8): winner = 'black' if click_coords in white_locations: selection = white_locations.index(click_coords) if turn_step == 0: turn_step = 1 if click_coords in valid_moves and selection != 100: white_locations[selection] = click_coords if click_coords in black_locations: black_piece = black_locations.index(click_coords) captured_pieces_white.append(black_pieces[black_piece]) if black_pieces[black_piece] == 'king': winner = 'white' black_pieces.pop(black_piece) black_locations.pop(black_piece) black_options = check_options( black_pieces, black_locations, 'black') white_options = check_options( white_pieces, white_locations, 'white') turn_step = 2 selection = 100 valid_moves = [] if turn_step > 1: if click_coords == (8, 8) or click_coords == (9, 8): winner = 'white' if click_coords in black_locations: selection = black_locations.index(click_coords) if turn_step == 2: turn_step = 3 if click_coords in valid_moves and selection != 100: black_locations[selection] = click_coords if click_coords in white_locations: white_piece = white_locations.index(click_coords) captured_pieces_black.append(white_pieces[white_piece]) if white_pieces[white_piece] == 'king': winner = 'black' white_pieces.pop(white_piece) white_locations.pop(white_piece) black_options = check_options( black_pieces, black_locations, 'black') white_options = check_options( white_pieces, white_locations, 'white') turn_step = 0 selection = 100 valid_moves = [] if event.type == pygame.KEYDOWN and game_over: if event.key == pygame.K_RETURN: game_over = False winner = '' white_pieces = ['rook', 'knight', 'bishop', 'king', 'queen', 'bishop', 'knight', 'rook', 'pawn', 'pawn', 'pawn', 'pawn', 'pawn', 'pawn', 'pawn', 'pawn'] white_locations = [(0, 0), (1, 0), (2, 0), (3, 0), (4, 0), (5, 0), (6, 0), (7, 0), (0, 1), (1, 1), (2, 1), (3, 1), (4, 1), (5, 1), (6, 1), (7, 1)] black_pieces = ['rook', 'knight', 'bishop', 'king', 'queen', 'bishop', 'knight', 'rook', 'pawn', 'pawn', 'pawn', 'pawn', 'pawn', 'pawn', 'pawn', 'pawn'] black_locations = [(0, 7), (1, 7), (2, 7), (3, 7), (4, 7), (5, 7), (6, 7), (7, 7), (0, 6), (1, 6), (2, 6), (3, 6), (4, 6), (5, 6), (6, 6), (7, 6)] captured_pieces_white = [] captured_pieces_black = [] turn_step = 0 selection = 100 valid_moves = [] black_options = check_options( black_pieces, black_locations, 'black') white_options = check_options( white_pieces, white_locations, 'white') if winner != '': game_over = True draw_game_over() pygame.display.flip() pygame.quit()
5. Explanation of Source Code
This Python code is for a two-player chess game implemented using the Pygame library. Let's break down the code into its main components and functionalities:
Importing Libraries:
- The code begins by importing the Pygame library, which is used for creating the graphical user interface of the chess game.
Initializing Pygame:
- Pygame is initialized using pygame.init(), which sets up the Pygame environment.
Setting Up Game Window:
- The code sets the dimensions of the game window with a width of 800 pixels and a height of 800 pixels.
- It also sets the window caption to "Two-Player Chess Game."
Defining Fonts and Clock:
- Three different fonts are defined for rendering text at various sizes.
- A clock object (timer) is created to control the frame rate of the game (60 frames per second).
Defining Game Variables and Images:
- Lists for white and black pieces and their initial positions on the chessboard are defined.
- Captured pieces for both players are tracked.
- Variables (turn_step, selection, and valid_moves) are used to manage the game state and player moves.
- Images for chess pieces (e.g., king, queen, rook) are loaded and scaled to appropriate sizes.
Defining Chess Piece Movement Functions:
- Several functions are defined to check the valid moves for each type of chess piece (e.g., pawn, rook, knight, bishop, queen, king).
- These functions return a list of valid move locations for a given piece at a specified position.
Drawing the Game Board:
- The draw_board() function is responsible for drawing the chessboard grid, status text, and a "FORFEIT" button.
Drawing Chess Pieces:
- The draw_pieces() function is used to draw the chess pieces on the board according to their current positions.
- If a piece is selected by a player, it is highlighted with a red or blue rectangle.
Checking Valid Moves and Drawing Highlights:
- The check_valid_moves() function checks the valid moves for the selected piece and returns a list of valid move locations.
- The draw_valid() function draws small circles at the valid move locations, indicating where the selected piece can be moved.
Handling Game Events:
- The code continuously checks for Pygame events, such as mouse clicks and key presses.
- Mouse clicks are used for selecting pieces and making moves.
- The "FORFEIT" button can be clicked to end the game.
- When the game is over, pressing the "ENTER" key restarts the game.
Drawing Captured Pieces:
- The draw_captured() function displays the captured pieces on the side of the game window for both players.
Checking for Check and Game Over:
- The draw_check() function draws a flashing square around the king of the player who is in check.
- The game checks for a checkmate or stalemate condition to determine the winner and end the game.
Main Game Loop:
- The main game loop (while run:) handles game updates, rendering, and event handling.
- It also manages the game state, player turns, and the end of the game.
Exiting the Game:
- The game loop continues until the player closes the game window, at which point Pygame is quit using pygame.quit().
6. Conclusion
In this Python Chess Game Tutorial with Pygame, we've embarked on an exciting journey into the world of game development. From setting up your development environment to implementing advanced features, you've gained valuable insights into creating your own chess game.
Now, it's your turn to bring your creativity and passion to the chessboard. As you continue to refine your game and explore new possibilities, you'll discover the joy of game development and the satisfaction of creating something truly unique.
So, go ahead and start coding your Python chess masterpiece today. The world of chess awaits your innovation and imagination!
7. FAQs
Q1. Is Pygame suitable for beginners in game development?
A1. Pygame is beginner-friendly and a great choice for those new to game development. Its simplicity and Python syntax make it accessible.
Q2. Can I customize the chessboard's appearance?
A2. Yes, you can customize the chessboard's appearance by modifying the graphics and colors in your game.
Q3. Are there any online resources for additional chess strategies?
A3. Numerous online resources provide tutorials and strategies to improve your chess skills.
Q4. How can I optimize my Python Chess Game for performance?
A4. Optimizing performance involves efficient coding and minimizing unnecessary calculations. Profiling tools can help identify bottlenecks.
Q5. Where can I find more Pygame tutorials for different games?
A5. You can find a variety of Pygame tutorials on websites, forums, and online courses dedicated to game development.
Q6. Is it possible to add an AI opponent to the game?
A6. Certainly! You can implement an AI opponent using various AI algorithms, such as minimax with alpha-beta pruning. Adding an AI opponent can make your chess game more challenging and enjoyable.
Creator: Avdhesh Varshney
That’s a wrap!
I hope you enjoyed this article
Did you like it? Let me know in the comments below 🔥 and you can support me by buying me a coffee.
And don’t forget to sign up to our email newsletter so you can get useful content like this sent right to your inbox!
Thanks!
Faraz 😊