Andrés Álvarez Iglesias
Posted on May 17, 2024
NOTE: This article was initially posted on my Substack, at https://andresalvareziglesias.substack.com/
Hi all!
In the first seven chapters of this series, we explored the power of the Django framework by building a basic application with functionalities like session management and database access. We've also learned how to create the infrastructure for this sample program using Docker, another powerful tool.
That was our primary goal: to learn Django and Docker. However, there's one thing remaining in our little demo project...
Articles in this series
- Chapter 1: Let the journey start
- Chapter 2: Create a containerized Django app with Gunicorn and Docker
- Chapter 3: Serve Django static files with NGINX
- Chapter 4: Adding a database to our stack
- Chapter 5: Applications and sites
- Chapter 6: Using the Django ORM
- Chapter 7: Users login, logout and register
Programming TicTacToe in Python
The TicTacToe is a very simple game, ideal for beginners. A possible implementation can be:
class TicTacToe:
def __init__(self, board):
self.board = board
self.winner = ""
def checkMove(self, position):
if self.board[position] == "E":
return True
return False
def makeMove(self, symbol, position):
if self.checkMove(position):
self.board = self.board[:position]+symbol+self.board[position+1:]
print(f"The player {symbol} makes a move at position {position}. Current board: [{self.board}]")
return True
print(f"Invalid movement! The position {position} is already occupied. Current board: [{self.board}]")
return False
def checkGameOver(self):
for i in range(0, 3):
# Vertical line
if self.board[i] != "E" and self.board[i] == self.board[i+3] and self.board[i] == self.board[i+6]:
self.winner = self.board[i]
print(f"Win condition reached (vertical line)! Winner: {self.winner} | Current board: [{self.board}]")
return True
# Horizontal line
if self.board[i*3] != "E" and self.board[i*3] == self.board[i*3+1] and self.board[i*3] == self.board[i*3+2]:
self.winner = self.board[i*3]
print(f"Win condition reached (horizontal line)! Winner: {self.winner} | Current board: [{self.board}]")
return True
# Diagonal lines
if self.board[0] != "E" and self.board[0] == self.board[4] and self.board[0] == self.board[8]:
self.winner = self.board[0]
print(f"Win condition reached (diagonal \\ line)! Winner: {self.winner} | Current board: [{self.board}]")
return True
elif self.board[2] != "E" and self.board[2] == self.board[4] and self.board[2] == self.board[6]:
self.winner = self.board[2]
print(f"Win condition reached (diagonal / line)! Winner: {self.winner} | Current board: [{self.board}]")
return True
# No more spaces to play
for i in range(0, 9):
if self.board[i] == "E":
return False
self.winner = "D"
print(f"No more spaces to play, draw! Winner: {self.winner} | Current board: [{self.board}]")
return True
Key features of this implementation:
- 3x3 Grid: The game board will always be a 3x3 grid with 9 positions.
- Two Players, Three Outcomes: The game allows two players and has three possible endings: victory for player O, victory for player X, or a draw.
- Winning Conditions: Any horizontal, vertical, or diagonal row of three tiles with the same symbol will result in a victory.
- Initial Board State: The class will maintain the current state of the board at the start of the game.
- Movement Tracking: Storing each movement in a database might be relevant for a more complex game like TicMagicalLine. This class allows to initialize the board with any initial state.
Can be easier, isn't it?
Playing Tic-Tac-Toe Against a Human Opponent
Now, let's explore a simple code example to test our class in Player-vs-Player (PvP) mode:
import os
from tictactoe import TicTacToe
def playerPlay(game, symbol):
validMove = False
while not validMove:
x, y = map(int, input(f'Player {symbol}: Make your move (x,y from 1 to 3): ').split(","))
position = ((x-1)*3)+(y-1)
validMove = game.makeMove(symbol, position)
if validMove:
print(f"Player {symbol}: Plays {symbol} at position {position} | State: {game.board}")
game.dumpBoard()
else:
print(f"Player {symbol}: Invalid move at position {position}! | State: {game.board}")
return game.checkGameOver()
emptyBoard = "EEEEEEEEE"
game = TicTacToe(emptyBoard)
player = 'O'
while not game.checkGameOver():
position = playerPlay(game, player)
if game.checkGameOver():
print(f"Player {player} wins!")
break
player = ('O' if player == 'X' else 'X')
The code will handle the following:
- Game Board Initialization: It will set up the initial empty game board.
- Turn Management: It will facilitate each player's turn until a winner is declared or the game reaches a draw.
Training the AI to Play Tic-Tac-Toe
Now, let's take things a step further and explore how to train our program to play Tic-Tac-Toe using machine learning. We'll be implementing a reward/punishment algorithm with TensorFlow and a small neural network.
While this approach might seem like overkill for a simple game like Tic-Tac-Toe, it serves as a fun introduction to the concepts of machine learning!
About the list
Among the Python and Docker posts, I will also write about other related topics (always tech and programming topics, I promise... with the fingers crossed), like:
- Software architecture
- Programming environments
- Linux operating system
- Etc.
If you found some interesting technology, programming language or whatever, please, let me know! I'm always open to learning something new!
About the author
I'm Andrés, a full-stack software developer based in Palma, on a personal journey to improve my coding skills. I'm also a self-published fantasy writer with four published novels to my name. Feel free to ask me anything!
Posted on May 17, 2024
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.