Tic-tac-toe, a famous game from childhood was given to me by my facilitator, Ms. Sophia A. Abubakar as a project. She insisted that my colleagues and I build this game in such a way it works on the dart console. As always, fear and tension built up immediately after she gave us this task on everyone's end and I was not exempted. I started my research using different techniques to achieve this task and below, is what I finally came up with.
Task Overview
- Build a 2-player Tic Tac Toe game (Version 1)
- Write an article detailing your steps and thought process
- Features of the game:
- Draw out the tic tac toe board on the console
- Handle user input for x and o and store it (For e.g, When a player 1 who is X wants to place an X on the screen, they can’t click the terminal. So you are going to replace this clicking by asking the user for a coordinate of where they want to place their piece.)
Features of The Game
- The game is played on a grid that's 3 squares by 3 squares.
- You are X, your friend (or the computer) is O. Players take turns putting their marks in empty squares.
- The first player to get 3 of their marks in a row (up, down, across, or diagonally) is the winner.
- When all 9 squares are full, the game is over and it is a draw.
Steps in Achieving this Task
Firstly, I imported the following packages from dart, they include:
dart:io
anddart:core
. The dart:core library provides basic collections, such as List, Map, and Set while dart:io library allows one to work with files, directories, sockets, processes, HTTP servers and clients, and more.I created a boolean and set it to false because at the start of the game, no player has won. Then I created another boolean and defined it as isXturn and set it as true. This boolean initiates whose turn it is to play.
I created a list of numbers from 1 to 9 and made possible combinations called co-ordinates that if any of these co-ordinates are played, it would decide that a player has won.
The board can be created using dash
(_ _)
and lines(| |)
, values from the arrays are then passed into each box.We create two variables called
generateBoard
andgetnextCharacter
. The first variable is used to create a function we would use to create our board in num 4 above, voidgenerateBoard()
. The second variable is used to get the user input of either X or O where we introduce the ternary operator?
, the shorthand for an if/else statement. This statement would ensure that when it is X turn, X will display and vice versa for O.We create an int variable called
int.parse(stdin.readLineSync)
from thedart:io
library to convert the number the player would input as string X or O.We use
isXturn = !isXturn;
to change player's turn and usecordinates[number - 1] = isXturn ? 'X' : 'O';
to change each player's co-ordinates. Normally, for a player to win, he or she must play 3 or at most 6 turns but in a case where if(movementCount == 9)
, it would be a draw. We will initiate theclearScreen();
to clear the screen if a draw occurs.We create another variable called
checkWinner
where the For loop is used to ascertain the winner at every move of each player and if winner==false (means no winner) and it breaks. However, there is a recursive function, a function that calls itself if(winner == false) getnextCharacter();
The game can be run in Mac OS or Windows depending on the type of Process used.
Process
is a thread that runs the application. We create an if else statement that tells the console to run the app if it is windows or Mac OS.
Note: This is a summary of the game itself. Below is the code snippet that can aid easy understanding of each step.
import 'dart:io';
import 'dart:core';
bool winner = false;
bool isXturn = true;
List<String> cordinates = ['1', '2', '3', '4', '5', '6', '7', '8', '9'];
List<String> combinations = ['012', '048', '036', '147', '246', '258', '345', '678'];
void main() {
generateBoard();
getnextCharacter();
}
int movementCount = 0;
//check if a combination is true or false for a player (X or 0)
bool checkCombination(String combination, String checkFor) {
//split the numbers in a list of integers
List<int> numbers = combination.split('').map((item) {
return int.parse(item);
}).toList();
bool match = false;
for (final item in numbers) {
if (cordinates[item] == checkFor) {
match = true;
} else {
match = false;
break;
}
}
return match;
}
void checkWinner(player) {
for (final item in combinations) {
bool combinationValidity = checkCombination(item, player);
if (combinationValidity == true) {
print('$player WON!');
winner = true;
break;
}
}
}
//get input, check winners
void getnextCharacter() {
//get input from player
print('Choose Number for ${isXturn == true ? "X" : "O"}');
int number = int.parse(stdin.readLineSync()!);
//change the value of selected number in cordinates
cordinates[number - 1] = isXturn ? 'X' : 'O';
//change player turn
isXturn = !isXturn;
//increment move count
movementCount++;
if (movementCount == 9) {
winner = true;
print('DRAW!');
} else {
//clear the console
clearScreen();
//redraw the board with the new information
generateBoard();
}
//
//Check Validity for players, declare winner
//
//check validity for player X
checkWinner('X');
//check validity for player O
checkWinner('O');
//until we have a winner, we call current function again
if (winner == false) getnextCharacter();
}
//clear console screen
void clearScreen() {
if (Platform.isWindows) {
print(Process.runSync("cls", [], runInShell: true).stdout);
} else {
print(Process.runSync("clear", [], runInShell: true).stdout);
}
}
//show current state of board
void generateBoard() {
print(' | | ');
print(' ${cordinates[0]} | ${cordinates[1]} | ${cordinates[2]} ');
print('___|___|___');
print(' | | ');
print(' ${cordinates[3]} | ${cordinates[4]} | ${cordinates[5]} ');
print('___|___|___');
print(' | | ');
print(' ${cordinates[6]} | ${cordinates[7]} | ${cordinates[8]} ');
print(' | | ');
}