This code implements a simple turn-based game similar to a...

July 5, 2025 at 11:35 PM

import time ROWS, COLS = 8, 8 HUMAN, COMPUTER = 'O', 'X' TIME_LIMIT = 5 def create_board(): #method for generating the 8x8 grid that the game will be played on return [['-' for _ in range(COLS)] for _ in range(ROWS)] def print_board(board): #method for displaying the board in a readable manner for the user print("\n " + ' '.join(str(i+1) for i in range(COLS))) for i, row in enumerate(board): print(f"{chr(ord('A')+i)} " + ' '.join(row)) print() def is_winner(board, player): #method for checking if either the player or the computer has made 4 in a row, starting with rows then doing columns for row in board: for c in range(COLS - 3): if all(cell == player for cell in row[c:c+4]): return True for c in range(COLS): for r in range(ROWS - 3): if all(board[r+i][c] == player for i in range(4)): return True return False def is_full(board): #method for easily checking if the game is a tie when nobody has won and there are no open spaces left return all(cell != '-' for row in board for cell in row) def get_legal_moves(board): #method for generating all the available cells that the user or computer can place in return [(r, c) for r in range(ROWS) for c in range(COLS) if board[r][c] == '-'] def apply_move(board, move, player): #method for adding the chosen move to the board r, c = move board[r][c] = player def undo_move(board, move): #method for undoing moves that have been done to the board (useful for ai to check future situations) r, c = move board[r][c] = '-' def evaluate(board): #large method for evaluating the scores of various moves on the board def evaluate_line(line, player, opponent): #submethod for evaluating the scores of lines of 4 throughout the board (checks threats and strong moves) line_str = ''.join(line) #winning and blocking winning lines if line_str == player * 4: return 1000000 if line_str == opponent * 4: return -100000 #threat detection with open spaces if line_str.count(player) == 3 and line_str.count('-') == 1: return 5000 #strong move if line_str.count(opponent) == 3 and line_str.count('-') == 1: return -8000 #urgent block if line_str.count(player) == 2 and line_str.count('-') == 2: return 300 if line_str.count(opponent) == 2 and line_str.count('-') == 2: return -1500 #strong block signal if line_str.count(player) == 1 and line_str.count('-') == 3: return 30 if line_str.count(opponent) == 1 and line_str.count('-') == 3: return -80 return 0 def score_lines(player): #method for scoring the opponent = HUMAN if player == COMPUTER else COMPUTER score = 0 #score rows for row in board: for c in range(COLS - 3): line = row[c:c+4] score += evaluate_line(line, player, opponent) #score columns for c in range(COLS): for r in range(ROWS - 3): line = [board[r+i][c] for i in range(4)] score += evaluate_line(line, player, opponent) return score return score_lines(COMPUTER) def alpha_beta(board, depth, alpha, beta, maximizing_player, start_time): if time.time() - start_time > TIME_LIMIT - 0.1 or is_winner(board, HUMAN) or is_winner(board, COMPUTER) or depth == 0: return evaluate(board), None best_move = None moves = get_legal_moves(board) #move ordering def move_score(move): r, c = move board[r][c] = COMPUTER if maximizing_player else HUMAN score = evaluate(board) board[r][c] = '-' return score moves.sort(key=move_score, reverse=maximizing_player) if maximizing_player: max_eval = -float('inf') for move in moves: apply_move(board, move, COMPUTER) eval_score, _ = alpha_beta(board, depth - 1, alpha, beta, False, start_time) undo_move(board, move) if eval_score > max_eval: max_eval = eval_score best_move = move alpha = max(alpha, eval_score) if beta <= alpha: break return max_eval, best_move else: min_eval = float('inf') for move in moves: apply_move(board, move, HUMAN) eval_score, _ = alpha_beta(board, depth - 1, alpha, beta, True, start_time) undo_move(board, move) if eval_score < min_eval: min_eval = eval_score best_move = move beta = min(beta, eval_score) if beta <= alpha: break return min_eval, best_move def get_computer_move(board): #method for using the previous methods to generate the computer's move start_time = time.time() depth = 1 best_move = None while depth <= 5 or time.time() - start_time < TIME_LIMIT - 0.1: eval_score, move = alpha_beta(board, depth, -float('inf'), float('inf'), True, start_time) if time.time() - start_time >= TIME_LIMIT: break if move is not None: best_move = move depth += 1 return best_move def parse_move(move_str): if len(move_str) < 2: return None row = ord(move_str[0].upper()) - ord('A') try: col = int(move_str[1]) - 1 except: return None if 0 <= row < ROWS and 0 <= col < COLS: return (row, col) return None def get_user_move(board): #method for getting the user input and applying it to the board while True: move_str = input("Enter your move (e.g. e5): ") move = parse_move(move_str) if move and board[move[0]][move[1]] == '-': return move print("Invalid move. Try again.") def main(): #main method for running the output of the program board = create_board() first = input("Do you want to go first? (y/n): ").lower() human_turn = first == 'y' print_board(board) while True: if human_turn: move = get_user_move(board) apply_move(board, move, HUMAN) else: print("Computer is thinking...") move = get_computer_move(board) if move: apply_move(board, move, COMPUTER) print(f"Computer moves to {chr(ord('A')+move[0])}{move[1]+1}") else: print("Computer cannot move.") print_board(board) if is_winner(board, HUMAN): print("You win!") break elif is_winner(board, COMPUTER): print("Computer wins!") break elif is_full(board): print("It's a tie!") break human_turn = not human_turn if __name__ == "__main__": main()

This code implements a simple turn-based game similar to a Connect Four-like game or grid-based "four in a row" game for two players: a human and a computer AI. Here’s an overview of what the code does:


1. Board Setup

  • It creates an 8x8 grid board initialized with '-', representing empty cells.

  • The board is displayed in a readable format (with row labels as letters A-H and column labels as numbers 1-8).

  • Example:

      1 2 3 4 5 6 7 8
    A - - - - - - - -
    B - - - - - - - -
    C - - - - - - - -
    D - - - - - - - -
    E - - - - - - - -
    F - - - - - - - -
    G - - - - - - - -
    H - - - - - - - -
    

2. Game Rules

  • Players take turns (human or computer's AI).

  • A player (HUMAN: 'O', or COMPUTER: 'X') chooses an empty cell to place their mark.

  • The first player to align 4 of their marks in a row, either:

    • Horizontally
    • Vertically
    • Diagonally wins the game.
  • If the board is filled and neither player has won, the game results in a tie.


3. Core Gameplay Logic

  • The game alternates between the human and the computer:
    • For the human's turn: The player inputs a move (e.g., "E5" for row E and column 5). The input is validated.
    • For the computer's turn: The AI calculates its move using the Alpha-Beta Pruning algorithm paired with a heuristic evaluation function.

4. Computer AI: Alpha-Beta Pruning

The computer uses Alpha-Beta Pruning, a depth-limited search algorithm, to make its decision:

  • Maximizing Player: The computer AI ('X') aims to maximize its advantage.
  • Minimizing Player: The human ('O') aims to minimize the computer's advantage.

Heuristic Evaluation:

  • The computer assigns scores to different board states based on:
    • Threats (lines of 3 or 2 marks with empty spaces).
    • Immediate winning or blocking opportunities.
    • Higher scores mean stronger positions for the computer, while lower (negative) scores mean better positions for the human.
  • The evaluation scores are calculated for rows, columns, and diagonals of length 4 on the board.

Time Constraint:

  • The AI calculates the optimal move recursively but halts its search if the computation time exceeds TIME_LIMIT (5 seconds).

5. Functions Breakdown

Here is a quick summary of important functions:

  • create_board(): Initializes the empty 8x8 board.
  • print_board(board): Displays the board in a user-friendly format.
  • is_winner(board, player): Checks if a given player ('O' or 'X') has 4 marks aligned in a row (horizontally, vertically, or diagonally).
  • is_full(board): Checks if the board is completely filled, indicating a tie.
  • get_legal_moves(board): Returns a list of all unoccupied cells (available moves).
  • apply_move(board, move, player): Places a player's mark on the board at the specified position.
  • undo_move(board, move): Reverts a move made on the board (used during AI evaluation to simulate future moves).

6. Execution Flow: main()

  • Starts the game with an empty board.
  • Asks the user if they want to play first.
  • Takes turns between the human and the computer, applying moves to the board until:
    • A player wins (4 aligned marks).
    • The board is full (tie).
  • The program declares the winner (human/computer) or announces a tie.

7. User Interaction

  • The human player inputs moves in algebraic notation (e.g., "B3", "E5") which are parsed into (row, col) coordinates via parse_move().
  • Invalid moves prompt the user to retry.

Summary

This program is a turn-based "four in a row" game on a fixed 8x8 grid, featuring a competitive AI opponent. The AI makes strategic decisions using Alpha-Beta Pruning with heuristic evaluation to maximize its chances of winning, while ensuring a responsive play experience by adhering to a time limit. The player interacts via text prompts, making it a simple console-based game.

Generate your own explanations
Download our vscode extension
Read other generated explanations

Built by @thebuilderjr
Sponsored by beam analytics
Read our terms and privacy policy
Forked from openai-quickstart-node