Low Level Design of Tic Tac Toe | System Design
Last Updated : 26 Aug, 2024
In classic games, few are as universally recognized and enjoyed as Tic Tac Toe. Despite its apparent simplicity, this game engages players of all ages in a battle of wits and strategy. In this article, we delve into the intricacies of designing a low-level structure for Tic Tac Toe that captures the essence of the game and highlights the underlying complexities.
Important Topics for Low Level Design of Tic Tac Toe
The Essence of Tic Tac Toe
Tic Tac Toe, known colloquially as "Xs and Os," is a two-player game typically played on a 3x3 grid. The objective is simple: be the first to form a horizontal, vertical, or diagonal line of three of your marks (either "X" or "O"). The elegance of the game lies in its deceptive complexity, while the rules are straightforward, devising an unbeatable strategy demands a keen understanding of the game's dynamics.
Rules of the game
Firstly let's understand the rules of the game:
- Setup: The game is played on a 3 * 3 grid. One player uses 'X' another player uses 'O' and each player takes turns making their moves.
- Winner: The game is won by the player placing his or her symbol in a row, column, or diagonal. The first player to get three symbols in a row wins the game. When the player reaches this, the game ends immediately.
- Draw: If all the grid cells are filled and no player has three symbols in a row, the game will be a tie or a draw.
- Illegal Moves: A player cannot place his or her symbol on a tile occupied by an opponent's symbol or their own symbol. The move must be made to an empty cell.
Representing the Game Board
At the heart of every game lies the game board. In our low-level design for Tic Tac Toe, we choose a 2D array or matrix to represent the board. Each cell of the array can take three possible values: empty, "X," or "O." This array forms the canvas upon which players will make their moves.
Python # Initialize an empty 3x3 Tic Tac Toe board board = [[' ' for _ in range(3)] for _ in range(3)]
Player Turns and Moves
In any game, managing player turns is crucial. We can represent the players using simple integers – player 1 and player 2. Their moves are translated to row and column indices on the game board.
Python current_player = 1 # Player 1 starts row = 1 column = 2 # Placing the current player's mark on the board board[row][column] = 'X' if current_player == 1 else 'O'
Validating Moves
Ensuring that players adhere to the rules is paramount. The low-level design includes a move validation process, verifying that the chosen cell is empty and within the bounds of the board.
Python def is_valid_move(row, column): return 0 <= row < 3 and 0 <= column < 3 and board[row][column] == ' ' # Example usage if is_valid_move(1, 2): # Perform the move else: print("Invalid move. Please choose an empty cell within the board.")
Determining the Winner
The climax of any Tic Tac Toe game is the declaration of a winner. Our low-level design accommodates a function to check for victory conditions after each move.
Python def check_winner(player): # Check rows, columns, and diagonals for three marks in a row # Return True if the player wins, False otherwise # Example usage if check_winner(1): print("Player 1 wins!") elif check_winner(2): print("Player 2 wins!")
Tying It All Together
Tic Tac Toe's low-level design is a harmonious interplay of game mechanics, data structures, and decision-making logic. From managing the game board to validating moves and determining victory, every element contributes to the immersive experience of the game.
So, the next time you engage in a friendly match of Tic Tac Toe, remember that behind the Xs and Os lies a thoughtfully crafted low-level design that brings a timeless game to life. As you strategize to outwit your opponent, you're also experiencing the result of careful planning and design – a testament to the enduring appeal of this classic pastime.
Complete Tic Tac Toe implementation
C++ #include <iostream> #include <vector> using namespace std; class TicTacToe { private: vector<vector<char> > board; // 3x3 game board int currentPlayer; // 1 for Player 1, 2 for Player 2 public: TicTacToe() { board = vector<vector<char> >(3, vector<char>(3, ' ')); currentPlayer = 1; } void printBoard() { for (int i = 0; i < 3; ++i) { for (int j = 0; j < 3; ++j) { cout << board[i][j]; if (j < 2) { cout << " | "; } } cout << endl; if (i < 2) { cout << "---------" << endl; } } } bool isBoardFull() { for (int i = 0; i < 3; ++i) { for (int j = 0; j < 3; ++j) { if (board[i][j] == ' ') { return false; } } } return true; } bool makeMove(int row, int column) { if (row < 0 || row >= 3 || column < 0 || column >= 3 || board[row][column] != ' ') { return false; // Invalid move } board[row][column] = (currentPlayer == 1) ? 'X' : 'O'; currentPlayer = 3 - currentPlayer; // Switch player (1 to 2 or // 2 to 1) return true; } bool checkWinner() { // Check rows, columns, and diagonals for a win for (int i = 0; i < 3; ++i) { if (board[i][0] != ' ' && board[i][0] == board[i][1] && board[i][1] == board[i][2]) { return true; // Row win } if (board[0][i] != ' ' && board[0][i] == board[1][i] && board[1][i] == board[2][i]) { return true; // Column win } } if (board[0][0] != ' ' && board[0][0] == board[1][1] && board[1][1] == board[2][2]) { return true; // Diagonal win } if (board[0][2] != ' ' && board[0][2] == board[1][1] && board[1][1] == board[2][0]) { return true; // Diagonal win } return false; } int getCurrentPlayer() { return currentPlayer; } }; int main() { TicTacToe game; int row, column; while (!game.isBoardFull() && !game.checkWinner()) { game.printBoard(); cout << "Player " << game.getCurrentPlayer() << ", enter your move (row and column): "; cin >> row >> column; if (game.makeMove(row, column)) { cout << "Move successful!" << endl; } else { cout << "Invalid move. Try again." << endl; } } game.printBoard(); if (game.checkWinner()) { cout << "Player " << (3 - game.getCurrentPlayer()) << " wins!" << endl; } else { cout << "It's a draw!" << endl; } return 0; }
Java import java.util.Scanner; public class TicTacToe { private char[][] board; // 3x3 game board private int currentPlayer; // 1 for Player 1, 2 for Player 2 public TicTacToe() { board = new char[3][3]; for (int i = 0; i < 3; ++i) { for (int j = 0; j < 3; ++j) { board[i][j] = ' '; } } currentPlayer = 1; } public void printBoard() { for (int i = 0; i < 3; ++i) { for (int j = 0; j < 3; ++j) { System.out.print(board[i][j]); if (j < 2) { System.out.print(" | "); } } System.out.println(); if (i < 2) { System.out.println("---------"); } } } public boolean isBoardFull() { for (int i = 0; i < 3; ++i) { for (int j = 0; j < 3; ++j) { if (board[i][j] == ' ') { return false; } } } return true; } public boolean makeMove(int row, int column) { if (row < 0 || row >= 3 || column < 0 || column >= 3 || board[row][column] != ' ') { return false; // Invalid move } board[row][column] = (currentPlayer == 1) ? 'X' : 'O'; currentPlayer = 3 - currentPlayer; // Switch player (1 to 2 or // 2 to 1) return true; } public boolean checkWinner() { // Check rows, columns, and diagonals for a win for (int i = 0; i < 3; ++i) { if (board[i][0] != ' ' && board[i][0] == board[i][1] && board[i][1] == board[i][2]) { return true; // Row win } if (board[0][i] != ' ' && board[0][i] == board[1][i] && board[1][i] == board[2][i]) { return true; // Column win } } if (board[0][0] != ' ' && board[0][0] == board[1][1] && board[1][1] == board[2][2]) { return true; // Diagonal win } if (board[0][2] != ' ' && board[0][2] == board[1][1] && board[1][1] == board[2][0]) { return true; // Diagonal win } return false; } public static void main(String[] args) { TicTacToe game = new TicTacToe(); Scanner scanner = new Scanner(System.in); int row, column; while (!game.isBoardFull() && !game.checkWinner()) { game.printBoard(); System.out.print( "Player " + game.currentPlayer + ", enter your move (row and column): "); row = scanner.nextInt(); column = scanner.nextInt(); if (game.makeMove(row, column)) { System.out.println("Move successful!"); } else { System.out.println( "Invalid move. Try again."); } } game.printBoard(); if (game.checkWinner()) { System.out.println("Player " + (3 - game.currentPlayer) + " wins!"); } else { System.out.println("It's a draw!"); } scanner.close(); } }
Python class TicTacToe: def __init__(self): self.board = [[' ' for _ in range(3)] for _ in range(3)] self.current_player = 1 def print_board(self): for row in self.board: print('|'.join(row)) print('-' * 5) def is_board_full(self): return all(cell != ' ' for row in self.board for cell in row) def make_move(self, row, column): if 0 <= row < 3 and 0 <= column < 3 and self.board[row][column] == ' ': self.board[row][column] = 'X' if self.current_player == 1 else 'O' # Switch player (1 to 2 or 2 to 1) self.current_player = 3 - self.current_player return True return False def check_winner(self): for i in range(3): if self.board[i][0] == self.board[i][1] == self.board[i][2] != ' ': return True # Row win if self.board[0][i] == self.board[1][i] == self.board[2][i] != ' ': return True # Column win if self.board[0][0] == self.board[1][1] == self.board[2][2] != ' ': return True # Diagonal win if self.board[0][2] == self.board[1][1] == self.board[2][0] != ' ': return True # Diagonal win return False # Main game loop if __name__ == "__main__": game = TicTacToe() while not game.is_board_full() and not game.check_winner(): game.print_board() row, column = map(int, input( f"Player {game.current_player}, enter your move (row and column): ").split()) if game.make_move(row, column): print("Move successful!") else: print("Invalid move. Try again.") game.print_board() if game.check_winner(): print(f"Player {3 - game.current_player} wins!") else: print("It's a draw!")
JavaScript class TicTacToe { constructor() { this.board = Array.from(Array(3), () => Array(3).fill(' ')); // 3x3 game board this.currentPlayer = 1; // 1 for Player 1, 2 for Player 2 } printBoard() { for (let i = 0; i < 3; ++i) { for (let j = 0; j < 3; ++j) { process.stdout.write(this.board[i][j]); if (j < 2) { process.stdout.write(' | '); } } console.log(); if (i < 2) { console.log('---------'); } } } isBoardFull() { for (let i = 0; i < 3; ++i) { for (let j = 0; j < 3; ++j) { if (this.board[i][j] === ' ') { return false; } } } return true; } makeMove(row, column) { if ( row < 0 || row >= 3 || column < 0 || column >= 3 || this.board[row][column] !== ' ' ) { return false; // Invalid move } this.board[row][column] = this.currentPlayer === 1 ? 'X' : 'O'; this.currentPlayer = 3 - this.currentPlayer; // Switch player (1 to 2 or 2 to 1) return true; } checkWinner() { // Check rows, columns, and diagonals for a win for (let i = 0; i < 3; ++i) { if ( this.board[i][0] !== ' ' && this.board[i][0] === this.board[i][1] && this.board[i][1] === this.board[i][2] ) { return true; // Row win } if ( this.board[0][i] !== ' ' && this.board[0][i] === this.board[1][i] && this.board[1][i] === this.board[2][i] ) { return true; // Column win } } if ( this.board[0][0] !== ' ' && this.board[0][0] === this.board[1][1] && this.board[1][1] === this.board[2][2] ) { return true; // Diagonal win } if ( this.board[0][2] !== ' ' && this.board[0][2] === this.board[1][1] && this.board[1][1] === this.board[2][0] ) { return true; // Diagonal win } return false; } } function main() { const game = new TicTacToe(); const readline = require('readline-sync'); let row, column; while (!game.isBoardFull() && !game.checkWinner()) { game.printBoard(); console.log(`Player ${game.currentPlayer}, enter your move (row and column): `); row = parseInt(readline.question('Row: ')); column = parseInt(readline.question('Column: ')); if (game.makeMove(row, column)) { console.log('Move successful!'); } else { console.log('Invalid move. Try again.'); } } game.printBoard(); if (game.checkWinner()) { console.log(`Player ${3 - game.currentPlayer} wins!`); } else { console.log("It's a draw!"); } } main(); // This code is contributed by Vikram_Shirsat
Conclusion
The game of Tic Tac Toe, often deemed simplistic, hides layers of intriguing design choices beneath its surface. From crafting the game board to managing turns and deciphering wins, every aspect intertwines to deliver an immersive gaming experience. As we delve into the low-level design using C++, we uncover the harmony between code and gameplay, reminding us that even seemingly uncomplicated games hold within them a realm of thoughtful intricacies.
So the next time you engage in a round of Tic Tac Toe, take a moment to appreciate the elegance of its design—a design that transforms an ordinary grid into a battlefield of strategic brilliance.
Similar Reads
Most Commonly Asked System Design Interview Problems/Questions This System Design Interview Guide will provide the most commonly asked system design interview questions and equip you with the knowledge and techniques needed to design, build, and scale your robust applications, for professionals and newbies Below are a list of most commonly asked interview probl
2 min read
How to Crack System Design Interview Round? In the System Design Interview round, You will have to give a clear explanation about designing large scalable distributed systems to the interviewer. This round may be challenging and complex for you because you are supposed to cover all the topics and tradeoffs within this limited time frame, whic
9 min read
System Design Interview Questions and Answers [2025] In the hiring procedure, system design interviews play a significant role for many tech businesses, particularly those that develop large, reliable software systems. In order to satisfy requirements like scalability, reliability, performance, and maintainability, an extensive plan for the system's a
7 min read
5 Common System Design Concepts for Interview Preparation In the software engineering interview process system design round has become a standard part of the interview. The main purpose of this round is to check the ability of a candidate to build a complex and large-scale system. Due to the lack of experience in building a large-scale system a lot of engi
12 min read
5 Tips to Crack Low-Level System Design Interviews Cracking low-level system design interviews can be challenging, but with the right approach, you can master them. This article provides five essential tips to help you succeed. These tips will guide you through the preparation process. Learn how to break down complex problems, communicate effectivel
6 min read
Chat Applications Design Problems
Designing Facebook Messenger | System Design Interview We are going to build a real-time Facebook messaging app, that can support millions of users. All the chat applications like Facebook Messenger, WhatsApp, Discord, etc. can be built using the same design. In this article, we will discuss the high-level architecture of the system as well as some spec
9 min read
Media Storage and Streaming Design Problems
System Design Netflix | A Complete Architecture Designing Netflix is a quite common question of system design rounds in interviews. In the world of streaming services, Netflix stands as a monopoly, captivating millions of viewers worldwide with its vast library of content delivered seamlessly to screens of all sizes. Behind this seemingly effortl
15+ min read
Design Dropbox - A System Design Interview Question System Design Dropbox, You might have used this file hosting service multiple times to upload and share files or images. System Design Dropbox is a quite common question in the system design round. In this article, we will discuss how to design a website like Dropbox.Important Topics for the Dropbox
14 min read