Flutter – Build an Advance Tic-Tac-Toe Game
In this article, we are going to create an advanced Tic-Tac-Toe app using by using some advanced packages available in Flutter. In this app you have only one screen on that screen we performed the whole Tic-Tac-Toe functionality. The game is to be played between two players ( one player human and the other computer). One of the players chooses ‘O’ and the other ‘X’ to mark their respective cells. The game starts with one of the players and the game ends when one of the players has one whole row/column/diagonal filled with her/his respective character (‘O’ or ‘X’ ). If no one wins, then the game is said to be drawn. A sample video is given below to get an idea about what we are going to do in this article.
Implementation
main.dart File:
Dart
import 'package:flutter/material.dart' ; import 'package:tic_toc/ui/theme/color.dart' ; import 'package:tic_toc/utils/game_logic.dart' ; void main() { runApp( const MyApp()); } class MyApp extends StatelessWidget { const MyApp({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return MaterialApp( debugShowCheckedModeBanner: false , home: GameScreen(), ); } } class GameScreen extends StatefulWidget { const GameScreen({Key? key}) : super(key: key); @override _GameScreenState createState() => _GameScreenState(); } class _GameScreenState extends State<GameScreen> { // adding the necessary variables String lastValue = "X" ; bool gameOver = false ; int turn = 0; // to check the draw String result = "" ; List< int > scoreboard = [ 0, 0, 0, 0, 0, 0, 0, 0 ]; // the score are for the different combination // of the game [Row1,2,3, Col1,2,3, Diagonal1,2]; // let's declare a new Game components Game game = Game(); // let's initi the GameBoard @override void initState() { // TODO: implement initState super.initState(); game.board = Game.initGameBoard(); print(game.board); } @override Widget build(BuildContext context) { double boardWidth = MediaQuery.of(context).size.width; return Scaffold( backgroundColor: MainColor.primaryColor, body: Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: [ Text( "Created by Daya Kumar " "${lastValue} turn" .toUpperCase(), style: TextStyle( color: Colors.white, fontSize: 20, ), ), SizedBox( height: 20.0, ), // now we will make the game board // but first we will create a Game class // that will contains all the data // and method that we will need Container( width: boardWidth, height: boardWidth, child: GridView.count( crossAxisCount: Game.boardlenth ~/ 3, // the ~/ operator allows you to evide to integer and return an Int as a result padding: EdgeInsets.all(16.0), mainAxisSpacing: 8.0, crossAxisSpacing: 8.0, children: List.generate(Game.boardlenth, (index) { return InkWell( onTap: gameOver ? null : () { // when we click we need to add the new value // to the board and refrech the screen // we need also to toggle the player // now we need to apply the click only if the field is empty // now let's create a button to repeat the game if (game.board![index] == "" ) { setState(() { game.board![index] = lastValue; turn++; gameOver = game.winnerCheck( lastValue, index, scoreboard, 3); if (gameOver) { result = "$lastValue is the Winner" ; } else if (!gameOver && turn == 9) { result = " It's a Draw! " ; gameOver = true ; } if (lastValue == "X" ) lastValue = "O" ; else lastValue = "X" ; }); } }, child: Container( width: Game.blocSize, height: Game.blocSize, decoration: BoxDecoration( color: MainColor.secondaryColor, borderRadius: BorderRadius.circular(25.0), ), child: Center( child: Text( game.board![index], style: TextStyle( color: game.board![index] == "X" ? Colors.redAccent : Colors.yellowAccent, fontSize: 64.0, ), ), ), ), ); }), ), ), SizedBox( height: 10.0, ), Text( result, style: TextStyle(color: Colors.white, fontSize: 54.0), ), ElevatedButton.icon( onPressed: () { setState(() { // erase the board game.board = Game.initGameBoard(); lastValue = "X" ; gameOver = false ; turn = 0; result = "" ; scoreboard = [0, 0, 0, 0, 0, 0, 0, 0]; }); }, icon: Icon(Icons.replay), label: Text( "RESTART" ), ), ], )); // the first step is organise // our project folder structure } } |
color.dart File:
In this file, we will define the color for our apps which will be used in multiple places. We will define all colors in this file so that we do not have to define a theme every time.
Dart
import 'package:flutter/material.dart' ; class MainColor { static Color primaryColor = Color(0xFF00061a); static Color secondaryColor = Color(0xFF97D5C9); static Color accentColor = Color(0xFF4169e8); } |
game_logic.dart File:
In this file, we will define all the logical parts of the app.
Dart
class Player { static const x = "X" ; static const o = "O" ; static const empty = "" ; } class Game { // we will creare a board of 3*3 blocks static final boardlenth = 9; static final blocSize = 100.0; // Creating the empty board List<String>? board; static List<String>? initGameBoard() => List.generate(boardlenth, (index) => Player.empty); // now we need to build the winner check algorithm // for this we need first to declare a scoreboard in our main file bool winnerCheck( String player, int index, List< int > scoreboard, int gridSize) { // first let's declare the row and col int row = index ~/ 3; int col = index % 3; int score = player == "X" ? 1 : -1; scoreboard[row] += score; scoreboard[gridSize + col] += score; if (row == col) scoreboard[2 * gridSize] += score; if (gridSize - 1 - col == row) scoreboard[2 * gridSize + 1] += score; // checking if we have 3 or -3 in the score board if (scoreboard.contains(3) || scoreboard.contains(-3)) { return true ; }; // by default it will return false return false ; } } |
Output:
Contact Us