Tic-tac-toe¶
Tic-tac-toe is a classic game where two players take turns marking spaces on a 3×3 grid, aiming to place three of their marks in a horizontal, vertical, or diagonal row.
Game Rules¶
- Players take turns placing their symbol (X or O) on an empty cell of the 3×3 grid
- The first player to form a line of three of their own symbol (horizontally, vertically, or diagonally) wins
- If all cells are filled and no player has formed a line, the game ends in a draw
Board Representation¶
The Tic-tac-toe board is represented as a 3×3 grid with positions labeled as follows:
a b c
+---+---+---+
3 | a3| b3| c3| 3
+---+---+---+
2 | a2| b2| c2| 2
+---+---+---+
1 | a1| b1| c1| 1
+---+---+---+
a b c
- Columns are labeled as 'a', 'b', and 'c'
- Rows are labeled as '1', '2', and '3'
- Each position is referenced by its column followed by its row (e.g., 'b2' for the center position)
Running a Game¶
To run a Tic-tac-toe game:
cs4341-referee tictactoe -p "python your_player.py" --visual
This will run a game where your player plays against itself. To specify a different opponent:
cs4341-referee tictactoe -p "python your_player.py" -p2 "python opponent_player.py" --visual
Player Communication¶
Initialization¶
At the start of the game, each player receives their symbol:
- First player receives:
"blue"(representing X) - Second player receives:
"orange"(representing O)
Move Format¶
The move format for Tic-tac-toe is simply the position where the player wants to place their symbol:
<column><row>
Examples:
a1(bottom-left corner)b2(center position)c3(top-right corner)
Game Flow¶
- The referee starts both player processes
- Each player is notified of their symbol
- Players take turns making moves:
- The current player is expected to send a valid move
- The referee validates the move and updates the game state
- The opponent receives the move made by the current player
- The game continues until someone wins or the board is full (draw)
Player Implementation¶
Here's a basic template for implementing a Tic-tac-toe player:
import sys
def main():
# Read initial symbol (X or O)
player_symbol = input().strip() # Will be "blue" or "orange"
# Initialize board (None represents empty cells)
board = {f"{col}{row}": None for col in "abc" for row in "123"}
while True:
try:
# Read opponent's move or game start
game_input = input().strip()
# Update board with opponent's move (if not first move)
if game_input:
board[game_input] = "opponent"
# Your move logic here
# For example, find the first empty cell:
move = next(pos for pos, val in board.items() if val is None)
# Update our internal board
board[move] = "me"
# Send move to referee
print(move, flush=True)
except EOFError:
break
if __name__ == "__main__":
main()
Web Visualization¶
When run with the --visual flag, the referee provides a web-based visualization of the game:

The visualization includes:
- Current board state
- Move history
- Player information
- Game status and results
Tips for Building a Strong Player¶
-
Corner Strategy: Starting with corner moves gives more opportunities for creating winning lines
-
Center Control: The center position (b2) provides the most opportunities for creating winning lines
-
Block Opponent: Always check if your opponent is about to win and block them
-
Fork Creation: Create positions where you have two potential winning moves, forcing your opponent to defend one and allowing you to win with the other
-
Minimax Algorithm: Implement the minimax algorithm with alpha-beta pruning for optimal play
Common Mistakes to Avoid¶
-
Invalid Move Format: Ensure your move is exactly in the format
<column><row>(e.g., "b2") -
Playing Occupied Cells: Always check that a cell is empty before making a move
-
Slow Response: Make sure your player responds within the timeout period
-
Buffer Flushing: Always use
flush=Truewith print statements to ensure your move is sent immediately -
Error Handling: Handle EOFError properly to gracefully exit when the game ends
Advanced Topics¶
Board Evaluation¶
For AI players, properly evaluating board positions is crucial. A simple evaluation function might assign:
- Win: +10
- Draw: 0
- Loss: -10
More sophisticated evaluations might consider:
- Number of potential winning lines
- Center control
- Corner occupation
Minimax Implementation¶
The minimax algorithm allows your player to find the optimal move by exploring possible future states:
def minimax(board, depth, is_maximizing):
if is_win(board, "me"):
return 10 - depth
if is_win(board, "opponent"):
return depth - 10
if is_full(board):
return 0
if is_maximizing:
best_score = -float('inf')
for move in get_empty_cells(board):
board[move] = "me"
score = minimax(board, depth + 1, False)
board[move] = None
best_score = max(score, best_score)
return best_score
else:
best_score = float('inf')
for move in get_empty_cells(board):
board[move] = "opponent"
score = minimax(board, depth + 1, True)
board[move] = None
best_score = min(score, best_score)
return best_score
With this foundation, you can build a perfect Tic-tac-toe player that never loses!