|
1 |
| -def print_tic_tac_toe(values): |
| 1 | +"""Tic Tac Toe Game |
| 2 | +
|
| 3 | +A two-player Tic Tac Toe game with score tracking. Players take turns marking |
| 4 | +a 3x3 grid, and the first to get three marks in a row (horizontal, vertical, |
| 5 | +or diagonal) wins. The game supports multiple rounds and maintains a scoreboard. |
| 6 | +""" |
| 7 | + |
| 8 | +import sys |
| 9 | +from typing import NoReturn |
| 10 | + |
| 11 | + |
| 12 | +def print_tic_tac_toe(values: list[str]) -> None: |
| 13 | + """Print the current state of the Tic Tac Toe board. |
| 14 | +
|
| 15 | + Args: |
| 16 | + values: List representing the 3x3 grid (indexes 0-8) |
| 17 | + """ |
2 | 18 | print("\n")
|
3 | 19 | print("\t | |")
|
4 | 20 | print(f"\t {values[0]} | {values[1]} | {values[2]}")
|
5 | 21 | print("\t_____|_____|_____")
|
6 |
| - |
7 | 22 | print("\t | |")
|
8 | 23 | print(f"\t {values[3]} | {values[4]} | {values[5]}")
|
9 | 24 | print("\t_____|_____|_____")
|
10 |
| - |
11 | 25 | print("\t | |")
|
12 |
| - |
13 | 26 | print(f"\t {values[6]} | {values[7]} | {values[8]}")
|
14 | 27 | print("\t | |")
|
15 | 28 | print("\n")
|
16 | 29 |
|
17 | 30 |
|
18 |
| -# Function to print the score-board |
19 |
| -def print_scoreboard(score_board): |
| 31 | +def print_scoreboard(score_board: dict[str, int]) -> None: |
| 32 | + """Display the current scoreboard for both players. |
| 33 | +
|
| 34 | + Args: |
| 35 | + score_board: Dictionary mapping player names to their scores |
| 36 | + """ |
20 | 37 | print("\t--------------------------------")
|
21 | 38 | print("\t SCOREBOARD ")
|
22 | 39 | print("\t--------------------------------")
|
23 | 40 |
|
24 | 41 | players = list(score_board.keys())
|
25 |
| - print("\t ", players[0], "\t ", score_board[players[0]]) |
26 |
| - print("\t ", players[1], "\t ", score_board[players[1]]) |
27 |
| - |
| 42 | + print(f"\t {players[0]}\t {score_board[players[0]]}") |
| 43 | + print(f"\t {players[1]}\t {score_board[players[1]]}") |
28 | 44 | print("\t--------------------------------\n")
|
29 | 45 |
|
30 | 46 |
|
31 |
| -# Function to check if any player has won |
32 |
| -def check_win(player_pos, cur_player): |
33 |
| - # All possible winning combinations |
34 |
| - soln = [ |
| 47 | +def check_win(player_pos: dict[str, list[int]], cur_player: str) -> bool: |
| 48 | + """Check if the current player has won by forming a valid line. |
| 49 | +
|
| 50 | + Args: |
| 51 | + player_pos: Dictionary mapping players ('X'/'O') to their occupied positions |
| 52 | + cur_player: Current player ('X' or 'O') to check for a win |
| 53 | +
|
| 54 | + Returns: |
| 55 | + True if the current player has a winning line, False otherwise |
| 56 | + """ |
| 57 | + # All possible winning position combinations (1-based indices) |
| 58 | + winning_combinations: list[list[int]] = [ |
35 | 59 | [1, 2, 3],
|
36 | 60 | [4, 5, 6],
|
37 |
| - [7, 8, 9], |
| 61 | + [7, 8, 9], # Horizontal |
38 | 62 | [1, 4, 7],
|
39 | 63 | [2, 5, 8],
|
40 |
| - [3, 6, 9], |
| 64 | + [3, 6, 9], # Vertical |
41 | 65 | [1, 5, 9],
|
42 |
| - [3, 5, 7], |
| 66 | + [3, 5, 7], # Diagonal |
43 | 67 | ]
|
44 | 68 |
|
45 |
| - # Loop to check if any winning combination is satisfied |
46 |
| - for x in soln: |
47 |
| - if all(y in player_pos[cur_player] for y in x): |
48 |
| - # Return True if any winning combination satisfies |
49 |
| - return True |
50 |
| - # Return False if no combination is satisfied |
51 |
| - return False |
| 69 | + # Check if any winning combination is fully occupied by the current player |
| 70 | + return any( |
| 71 | + all(pos in player_pos[cur_player] for pos in combo) |
| 72 | + for combo in winning_combinations |
| 73 | + ) |
| 74 | + |
| 75 | + |
| 76 | +def check_draw(player_pos: dict[str, list[int]]) -> bool: |
| 77 | + """Check if the game is a draw (all positions filled with no winner). |
| 78 | +
|
| 79 | + Args: |
| 80 | + player_pos: Dictionary mapping players ('X'/'O') to their occupied positions |
52 | 81 |
|
| 82 | + Returns: |
| 83 | + True if all 9 positions are filled, False otherwise |
| 84 | + """ |
| 85 | + return len(player_pos["X"]) + len(player_pos["O"]) == 9 |
53 | 86 |
|
54 |
| -# Function to check if the game is drawn |
55 |
| -def check_draw(player_pos): |
56 |
| - if len(player_pos["X"]) + len(player_pos["O"]) == 9: |
57 |
| - return True |
58 |
| - return False |
59 | 87 |
|
| 88 | +def single_game(cur_player: str) -> str: |
| 89 | + """Run a single game of Tic Tac Toe and return the result. |
60 | 90 |
|
61 |
| -# Function for a single game of Tic Tac Toe |
62 |
| -def single_game(cur_player): |
63 |
| - # Represents the Tic Tac Toe |
64 |
| - values = [" " for x in range(9)] |
| 91 | + Args: |
| 92 | + cur_player: Initial player for the game ('X' or 'O') |
65 | 93 |
|
66 |
| - # Stores the positions occupied by X and O |
67 |
| - player_pos = {"X": [], "O": []} |
| 94 | + Returns: |
| 95 | + 'X' if X wins, 'O' if O wins, 'D' if it's a draw |
| 96 | + """ |
| 97 | + # Initialize empty game board (0-8 map to positions 1-9) |
| 98 | + board: list[str] = [" " for _ in range(9)] |
| 99 | + # Track positions occupied by each player (stores 1-9 values) |
| 100 | + player_positions: dict[str, list[int]] = {"X": [], "O": []} |
68 | 101 |
|
69 |
| - # Game Loop for a single game of Tic Tac Toe |
70 | 102 | while True:
|
71 |
| - print_tic_tac_toe(values) |
| 103 | + print_tic_tac_toe(board) |
72 | 104 |
|
73 |
| - # Try exception block for MOVE input |
| 105 | + # Get and validate player's move |
74 | 106 | try:
|
75 |
| - print("Player ", cur_player, " turn. Which box? : ", end="") |
76 |
| - move = int(input()) |
| 107 | + move_input: str = input( |
| 108 | + f"Player {cur_player}'s turn. Enter position (1-9): " |
| 109 | + ) |
| 110 | + move: int = int(move_input) |
77 | 111 | except ValueError:
|
78 |
| - print("Wrong Input!!! Try Again") |
| 112 | + print("Invalid input! Please enter a number between 1-9.\n") |
79 | 113 | continue
|
80 | 114 |
|
81 |
| - # Sanity check for MOVE inout |
82 |
| - if move < 1 or move > 9: |
83 |
| - print("Wrong Input!!! Try Again") |
| 115 | + # Validate move range |
| 116 | + if not (1 <= move <= 9): |
| 117 | + print("Invalid position! Please enter a number between 1-9.\n") |
84 | 118 | continue
|
85 | 119 |
|
86 |
| - # Check if the box is not occupied already |
87 |
| - if values[move - 1] != " ": |
88 |
| - print("Place already filled. Try again!!") |
| 120 | + # Check if position is already occupied |
| 121 | + if board[move - 1] != " ": |
| 122 | + print("That position is already taken! Try another.\n") |
89 | 123 | continue
|
90 | 124 |
|
91 |
| - # Update game information |
| 125 | + # Update game state with valid move |
| 126 | + board[move - 1] = cur_player |
| 127 | + player_positions[cur_player].append(move) |
92 | 128 |
|
93 |
| - # Updating grid status |
94 |
| - values[move - 1] = cur_player |
95 |
| - |
96 |
| - # Updating player positions |
97 |
| - player_pos[cur_player].append(move) |
98 |
| - |
99 |
| - # Function call for checking win |
100 |
| - if check_win(player_pos, cur_player): |
101 |
| - print_tic_tac_toe(values) |
102 |
| - print("Player ", cur_player, " has won the game!!") |
103 |
| - print("\n") |
| 129 | + # Check for win |
| 130 | + if check_win(player_positions, cur_player): |
| 131 | + print_tic_tac_toe(board) |
| 132 | + print(f"Player {cur_player} wins!\n") |
104 | 133 | return cur_player
|
105 | 134 |
|
106 |
| - # Function call for checking draw game |
107 |
| - if check_draw(player_pos): |
108 |
| - print_tic_tac_toe(values) |
109 |
| - print("Game Drawn") |
110 |
| - print("\n") |
| 135 | + # Check for draw |
| 136 | + if check_draw(player_positions): |
| 137 | + print_tic_tac_toe(board) |
| 138 | + print("Game ended in a draw!\n") |
111 | 139 | return "D"
|
112 | 140 |
|
113 |
| - # Switch player moves |
114 |
| - if cur_player == "X": |
115 |
| - cur_player = "O" |
116 |
| - else: |
117 |
| - cur_player = "X" |
| 141 | + # Switch players for next turn |
| 142 | + cur_player = "O" if cur_player == "X" else "X" |
118 | 143 |
|
119 | 144 |
|
120 |
| -if __name__ == "__main__": |
121 |
| - print("Player 1") |
122 |
| - player1 = input("Enter the name : ") |
123 |
| - print("\n") |
124 |
| - |
125 |
| - print("Player 2") |
126 |
| - player2 = input("Enter the name : ") |
| 145 | +def main() -> NoReturn: |
| 146 | + """Main game loop handling multiple rounds and score tracking.""" |
| 147 | + # Get player names |
| 148 | + print("Player 1, please enter your name:") |
| 149 | + player1: str = input().strip() |
| 150 | + print("\nPlayer 2, please enter your name:") |
| 151 | + player2: str = input().strip() |
127 | 152 | print("\n")
|
128 | 153 |
|
129 |
| - # Stores the player who chooses X and O |
130 |
| - cur_player = player1 |
131 |
| - |
132 |
| - # Stores the choice of players |
133 |
| - player_choice = {"X": "", "O": ""} |
| 154 | + # Initialize game state |
| 155 | + current_chooser: str = player1 # Player who chooses X/O for the round |
| 156 | + player_marks: dict[str, str] = {"X": "", "O": ""} # Maps mark to player name |
| 157 | + scoreboard: dict[str, int] = {player1: 0, player2: 0} |
| 158 | + mark_options: list[str] = ["X", "O"] |
134 | 159 |
|
135 |
| - # Stores the options |
136 |
| - options = ["X", "O"] |
| 160 | + print_scoreboard(scoreboard) |
137 | 161 |
|
138 |
| - # Stores the scoreboard |
139 |
| - score_board = {player1: 0, player2: 0} |
140 |
| - print_scoreboard(score_board) |
141 |
| - |
142 |
| - # Game Loop for a series of Tic Tac Toe |
143 |
| - # The loop runs until the players quit |
| 162 | + # Main game loop (multiple rounds) |
144 | 163 | while True:
|
145 |
| - # Player choice Menu |
146 |
| - print("Turn to choose for", cur_player) |
147 |
| - print("Enter 1 for X") |
148 |
| - print("Enter 2 for O") |
149 |
| - print("Enter 3 to Quit") |
| 164 | + print(f"It's {current_chooser}'s turn to choose a mark:") |
| 165 | + print("1 - Choose X") |
| 166 | + print("2 - Choose O") |
| 167 | + print("3 - Quit the game") |
150 | 168 |
|
151 |
| - # Try exception for CHOICE input |
| 169 | + # Get and validate player's choice |
152 | 170 | try:
|
153 |
| - choice = int(input()) |
| 171 | + choice_input: str = input("Enter your choice: ").strip() |
| 172 | + choice: int = int(choice_input) |
154 | 173 | except ValueError:
|
155 |
| - print("Wrong Input!!! Try Again\n") |
| 174 | + print("Invalid input! Please enter a number (1-3).\n") |
156 | 175 | continue
|
157 | 176 |
|
158 |
| - # Conditions for player choice |
159 |
| - if choice == 1: |
160 |
| - player_choice["X"] = cur_player |
161 |
| - if cur_player == player1: |
162 |
| - player_choice["O"] = player2 |
163 |
| - else: |
164 |
| - player_choice["O"] = player1 |
165 |
| - |
166 |
| - elif choice == 2: |
167 |
| - player_choice["O"] = cur_player |
168 |
| - if cur_player == player1: |
169 |
| - player_choice["X"] = player2 |
170 |
| - else: |
171 |
| - player_choice["X"] = player1 |
172 |
| - |
173 |
| - elif choice == 3: |
174 |
| - print("Final Scores") |
175 |
| - print_scoreboard(score_board) |
176 |
| - break |
177 |
| - |
178 |
| - else: |
179 |
| - print("Wrong Choice!!!! Try Again\n") |
180 |
| - |
181 |
| - # Stores the winner in a single game of Tic Tac Toe |
182 |
| - winner = single_game(options[choice - 1]) |
183 |
| - |
184 |
| - # Edits the scoreboard according to the winner |
185 |
| - if winner != "D": |
186 |
| - player_won = player_choice[winner] |
187 |
| - score_board[player_won] = score_board[player_won] + 1 |
188 |
| - |
189 |
| - print_scoreboard(score_board) |
190 |
| - # Switch player who chooses X or O |
191 |
| - if cur_player == player1: |
192 |
| - cur_player = player2 |
193 |
| - else: |
194 |
| - cur_player = player1 |
| 177 | + # Process choice |
| 178 | + if choice == 3: |
| 179 | + # Exit game |
| 180 | + print("Final Scores:") |
| 181 | + print_scoreboard(scoreboard) |
| 182 | + sys.exit(0) |
| 183 | + elif choice not in (1, 2): |
| 184 | + print("Invalid choice! Please enter 1, 2, or 3.\n") |
| 185 | + continue |
| 186 | + |
| 187 | + # Assign marks based on choice |
| 188 | + chosen_mark: str = mark_options[choice - 1] |
| 189 | + player_marks[chosen_mark] = current_chooser |
| 190 | + other_mark: str = "O" if chosen_mark == "X" else "X" |
| 191 | + player_marks[other_mark] = player2 if current_chooser == player1 else player1 |
| 192 | + |
| 193 | + # Run a single game and update score |
| 194 | + round_winner: str = single_game(chosen_mark) |
| 195 | + if round_winner != "D": |
| 196 | + winning_player: str = player_marks[round_winner] |
| 197 | + scoreboard[winning_player] += 1 |
| 198 | + |
| 199 | + # Show updated scores |
| 200 | + print_scoreboard(scoreboard) |
| 201 | + |
| 202 | + # Switch mark chooser for next round |
| 203 | + current_chooser = player2 if current_chooser == player1 else player1 |
| 204 | + |
| 205 | + |
| 206 | +if __name__ == "__main__": |
| 207 | + main() |
0 commit comments