I used a brute force logic to develop an algorithm for tic-tac-toe.
Firstly, there are only 8 triads of winning points or moves: three vertical, three horizontal and 2 diagonals.
Players play taking turns or making moves alternately. Player 1 makes a maximum of 5 moves and player
2 makes a maximum of 4 moves because there are a maximum of 9 moves to be made and player 1 begins the game.
Furthermore, player 1 has already made 2 moves before getting his first chance to form a winning line.
Players take turns alternately which means that when player 1 gets his first chance to form a line,
player 2 has already made 2 moves of his own. So player 1 can only form a line from move 5. Player 2
can only form his first line at move 6. Player 1 gets his second chance to win at move 7 and his third
and last chance at move 9. Similarly, player 2 gets his second and last chance at move 8.
Every time there is a chance to form a winning line, all possible permutations and combinations of
the current players moves, taken three at a time, are compared with all 8 winning triads. If a match is found,
the current player wins. If player 1 forms a line first, player 2 does not get a chance to continue the game.
The game has 3 versions: PHP, Java and C#
PHP Version
It can be played via the command-line executable of your PHP installation.
In the game of tic-tac-toe there is a 3X3 grid or board.The game is for two players. The players 1 and 2 take turns to mark the cells of the grid with their mark which is a zero or a cross.
The first player to complete a vertical, horizontal or diagonal triad of zeroes or crosses, wins.
In this implementation, I have used the OOPs or Object Oriented Programming features of PHP.
I have divided the functionality and roles or responsibilities between various classes as follows.
Player makes Move on Board to play Game. So the classes are:
- Move
- Board
- Player
- Game
First we discuss the move class:
Move:
Move made by either of the players.
class Move
{
private $row; // between 1 and 3
private $column; //between 1 and 3 on the 3x3 board
private $isValid; //whether the move is valid or not
//getters and setters for the properties
public function setRow($i)
{
$this->row = $i;
}
public function setColumn($j)
{
$this->column = $j;
}
public function setValid($valid)
{
$this->isValid = $valid;
}
public function getRow()
{
return $this->row;
}
public function getColumn()
{
return $this->column;
}
public function getValid()
{
return $this->isValid;
}
}
Then comes the Board class where the moves are made.
Board:
The board on which the game is played.
class Board
{
private $cells = array(); //the 3x3 grid of cells
public function __construct()
{
$row1 = array(" ", " ", " ");
$row2 = array(" ", " ", " ");
$row3 = array(" ", " ", " ");
$this->cells[0] = $row1;
$this->cells[1] = $row2;
$this->cells[2] = $row3;
}
//display the board with moves made so far
public function display()
{
for($i = 0; $i < 3; $i++)
{
for($j = 0; $j < 3; $j++) { if($this->cells[$i][$j] == " ")
{
echo ($i + 1).", ".($j + 1)."\t";
}
else
{
echo $this->cells[$i][$j]."\t";
}
}
echo "\n\n";
}
}
//check if a cell is already occupied or not
public function checkAvailable($move)
{
$i = $move->getRow();
$j = $move->getColumn();
$valid1 = (($i >= 1 && $i <= 3) && ($j >= 1 && $j <= 3));
if($valid1)
{
$valid2 = ($this->cells[$i - 1][$j - 1] == " ");
}
else
{
$valid2 = false;
}
$valid3 = ($valid1 && $valid2);
$move->setValid($valid3);
return $move;
}
//put a cross or zero in a cell if the move is valid
public function markCell($move, $mark)
{
if($move->getValid())
{
$i = $move->getRow();
$j = $move->getColumn();
$this->cells[$i - 1][$j - 1] = $mark;
}
else
{
echo "INVALID MOVE!\n\n";
}
}
}
The Player class denotes the players who make moves on the board.
Player:
Either of the two players.
class Player
{
private $playerNum; //player 1 or 2
private $playerMark; // '0' or 'X'
private $winnerOrLoser;
private $moves = array(); //list of moves made by player
private $g; //the game being played
//getters and setters
public function setPlayerNum($num)
{
$this->playerNum = $num;
}
public function setPlayerMark($mark)
{
$this->playerMark = $mark;
}
public function setPlayerWinnerLoser($winnerOrLoser)
{
$this->winnerOrLoser = $winnerOrLoser;
}
public function getPlayerNum()
{
return $this->playerNum;
}
public function getPlayerMark()
{
return $this->playerMark;
}
public function getPlayerWinLose()
{
return $this->winnerOrLoser;
}
public function getPlayerMoves()
{
return $this->moves;
}
//the player can put x or 0 by choosing the cell (row and column)
public function makeMove($board, $move)
{
$move = $board->checkAvailable($move);
$mark = $this->getPlayerMark();
$board->markCell($move, $mark);
if($move->getValid())
{
$this->addMove($move);
$this->getGame()->setMovesTillNow();
}
$board->display();
}
//if move is valid, add the move to the player's list of moves
public function addMove($move)
{
$this->moves[] = $move;
}
public function setGame($game)
{
$this->g = $game;
}
public function getGame()
{
return $this->g;
}
}
The Game class is the functionality of the game with all its rules.
Game:
The game being played.
class Game
{
private $whoseTurn; //player 1 or 2
private static $movesTillNow = 0; //how many moves till now
private $gameOver; //is game over yet?
private $winningMoves; //list of combination of moves which can win the game
private $winner = null;
private $winning_moves;
public function __construct()
{
//winning moves
$this->winning_moves = array();
//row wise
$move01 = new Move();
$move01->setRow(1);
$move01->setColumn(1);
$move02 = new Move();
$move02->setRow(1);
$move02->setColumn(2);
$move03 = new Move();
$move03->setRow(1);
$move03->setColumn(3);
$move0 = array($move01, $move02, $move03);
$this->winning_moves[0] = $move0;
$move11 = new Move();
$move11->setRow(2);
$move11->setColumn(1);
$move12 = new Move();
$move12->setRow(2);
$move12->setColumn(2);
$move13 = new Move();
$move13->setRow(2);
$move13->setColumn(3);
$move1 = array($move11, $move12, $move13);
$this->winning_moves[1] = $move1;
$move21 = new Move();
$move21->setRow(3);
$move21->setColumn(1);
$move22 = new Move();
$move22->setRow(3);
$move22->setColumn(2);
$move23 = new Move();
$move23->setRow(3);
$move23->setColumn(3);
$move2 = array($move21, $move22, $move23);
$this->winning_moves[2] = $move2;
//column wise
$move31 = new Move();
$move31->setRow(1);
$move31->setColumn(1);
$move32 = new Move();
$move32->setRow(2);
$move32->setColumn(1);
$move33 = new Move();
$move33->setRow(3);
$move33->setColumn(1);
$move3 = array($move31, $move32, $move33);
$this->winning_moves[3] = $move3;
$move41 = new Move();
$move41->setRow(1);
$move41->setColumn(2);
$move42 = new Move();
$move42->setRow(2);
$move42->setColumn(2);
$move43 = new Move();
$move43->setRow(3);
$move43->setColumn(2);
$move4 = array($move41, $move42, $move43);
$this->winning_moves[4] = $move4;
$move51 = new Move();
$move51->setRow(1);
$move51->setColumn(3);
$move52 = new Move();
$move52->setRow(2);
$move52->setColumn(3);
$move53 = new Move();
$move53->setRow(3);
$move53->setColumn(3);
$move5 = array($move51, $move52, $move53);
$this->winning_moves[5] = $move5;
//diagonally
$move61 = new Move();
$move61->setRow(1);
$move61->setColumn(1);
$move62 = new Move();
$move62->setRow(2);
$move62->setColumn(2);
$move63 = new Move();
$move63->setRow(3);
$move63->setColumn(3);
$move6 = array($move61, $move62, $move63);
$this->winning_moves[6] = $move6;
$move71 = new Move();
$move71->setRow(1);
$move71->setColumn(3);
$move72 = new Move();
$move72->setRow(2);
$move72->setColumn(2);
$move73 = new Move();
$move73->setRow(3);
$move73->setColumn(1);
$move7 = array($move71, $move72, $move73);
$this->winning_moves[7] = $move7;
}
//getters and setters
public function getWhoseTurn()
{
return $this->whoseTurn;
}
public function setWhoseTurn($player)
{
$this->whoseTurn = $player->getPlayerNum();
}
public function getGameOver()
{
return $this->gameOver;
}
public function setGameOver($gameOver)
{
$this->gameOver = $gameOver;
}
public function setMovesTillNow()
{
self::$movesTillNow++;
}
public function getMovesTillNow()
{
return self::$movesTillNow;
}
public function setWinner($winner)
{
$this->winner = $winner;
}
public function getWinner()
{
return $this->winner;
}
//check if winning moves have been made by either player
public function checkWinningMoves($player)
{
$movesTillNow = $this->getMovesTillNow();
$whoseTurn = $this->getWhoseTurn();
$playerMoves = $player->getPlayerMoves();
$moves = $movesTillNow;
$winning_moves1 = $this->winning_moves;
switch($whoseTurn)
{
case 1:
if($moves < 5)
{
return false;
}
else
{
if($moves == 5)
{
$player1_set1 = array($playerMoves[0], $playerMoves[1], $playerMoves[2]);
for($i = 0; $i < 8; $i++) { if($this->checkSubset($player1_set1, $winning_moves1[$i]))
{
return true;
}
}
}
if($moves == 7)
{
$player1_set2 = array($playerMoves[0], $playerMoves[1], $playerMoves[3]);
$player1_set4 = array($playerMoves[0], $playerMoves[2], $playerMoves[3]);
$player1_set7 = array($playerMoves[1], $playerMoves[2], $playerMoves[3]);
for($i = 0; $i < 8; $i++) { if($this->checkSubset($player1_set2, $winning_moves1[$i]) ||
$this->checkSubset($player1_set4, $winning_moves1[$i]) ||
$this->checkSubset($player1_set7, $winning_moves1[$i]) )
{
return true;
}
}
}
if($moves == 9)
{
$player1_set3 = array($playerMoves[0], $playerMoves[1], $playerMoves[4]);
$player1_set5 = array($playerMoves[0], $playerMoves[2], $playerMoves[4]);
$player1_set6 = array($playerMoves[0], $playerMoves[3], $playerMoves[4]);
$player1_set8 = array($playerMoves[1], $playerMoves[2], $playerMoves[4]);
$player1_set9 = array($playerMoves[1], $playerMoves[3], $playerMoves[4]);
$player1_set10 = array($playerMoves[2], $playerMoves[3], $playerMoves[4]);
for($i = 0; $i < 8; $i++) { if($this->checkSubset($player1_set3, $winning_moves1[$i]) ||
$this->checkSubset($player1_set5, $winning_moves1[$i]) || $this->checkSubset($player1_set6, $winning_moves1[$i]) ||
$this->checkSubset($player1_set8, $winning_moves1[$i]) || $this->checkSubset($player1_set9, $winning_moves1[$i]) ||
$this->checkSubset($player1_set10, $winning_moves1[$i]))
{
return true;
}
}
}
return false;
}
break;
case 2:
if($moves < 6)
{
return false;
}
else
{
if($moves == 6)
{
$player2_set1 = array($playerMoves[0], $playerMoves[1], $playerMoves[2]);
for($i = 0; $i < 8; $i++) { if($this->checkSubset($player2_set1, $winning_moves1[$i]))
{
return true;
}
}
}
if($moves == 8)
{
$player2_set2 = array($playerMoves[0], $playerMoves[1], $playerMoves[3]);
$player2_set3 = array($playerMoves[0], $playerMoves[2], $playerMoves[3]);
$player2_set4 = array($playerMoves[1], $playerMoves[2], $playerMoves[3]);
for($i = 0; $i < 8; $i++) { if($this->checkSubset($player2_set2, $winning_moves1[$i]) || $this->checkSubset($player2_set3, $winning_moves1[$i]) ||
$this->checkSubset($player2_set4, $winning_moves1[$i]))
{
return true;
}
}
}
return false;
}
break;
default:
return false;
}
}
//check if player moves match the winning sequence
private function checkSubset($subset, $winning_row)
{
$count = 0;
for($i = 0; $i < 3; $i++)
{
for($j = 0; $j < 3; $j++) { if($subset[$i]->getRow() == $winning_row[$j]->getRow() && $subset[$i]->getColumn() == $winning_row[$j]->getColumn())
{
$count++;
}
}
}
return ($count == 3);
}
}
Putting it all together.
<?php
require("includes/move.php"); //the Move class
require("includes/player.php"); //the Player class
require("includes/board.php"); //the Board class
require("includes/game.php"); //the Game class
function main() //where all the action is
{
$game = new Game();
$player1 = new Player();
$player1->setPlayerNum(1);
$player1->setPlayerMark('X');
$player1->setGame($game);
$player2 = new Player();
$player2->setPlayerNum(2);
$player2->setPlayerMark('0');
$player2->setGame($game);
$b = new Board();
$b->display();
$game->setWhoseTurn($player1);
$game->setGameOver(false);
$status = $game->getGameOver();
do
{
$movesNow = $game->getMovesTillNow();
if($movesNow == 9)
{
if($game->getWinner() == null)
{
echo "TIE!";
break;
}
}
$turn = $game->getWhoseTurn();
echo "PLAYER $turn:\n\n";
$row = 0; $column = 0;
echo "Enter row: ";
trim(fscanf(STDIN, "%d\n", $row));
echo "Enter column: ";
trim(fscanf(STDIN, "%d\n", $column));
echo "\n";
$move = new Move();
$move->setRow($row);
$move->setColumn($column);
switch($turn)
{
case 1:
$player1->makeMove($b, $move);
if($game->checkWinningMoves($player1))
{
$game->setWinner($player1);
echo "PLAYER 1 WINS!\n\n";
$game->setGameOver(true);
}
else
{
if($move->getValid())
{
$movesNow = $game->getMovesTillNow();
echo "MOVE NUMBER: $movesNow\n\n";
$game->setWhoseTurn($player2);
}
}
break;
case 2:
$player2->makeMove($b, $move);
if($game->checkWinningMoves($player2))
{
$game->setWinner($player2);
echo "PLAYER 2 WINS!\n\n";
$game->setGameOver(true);
}
else
{
if($move->getValid())
{
$movesNow = $game->getMovesTillNow();
echo "MOVE NUMBER: $movesNow\n\n";
$game->setWhoseTurn($player1);
}
}
break;
default:
echo "ERROR!\n\n";
break;
}
$status = $game->getGameOver();
}while(!$status);
}
main(); //invoking the game play
?>
This implementation is not perfect by any means. Any suggestions for improvement are welcome. Screenshots given below:
Java Version
Here is an elementary tic-tac-toe or noughts and crosses game made in Java.
It can be played via the java interpreter from the command line. In the game of tic-tac-toe there is a 3X3 grid or board.The game is for two players. The players take turns to mark the cells of the grid with their mark which is a zero or a cross.
The first player to complete a vertical, horizontal or diagonal triad of zeroes or crosses, wins.
The PHP version can be found here
Player makes Move on Board to play Game. So the classes are:
- Move
- Board
- Player
- Game
- TicTacToe
There is one new class “TicTacToe” because Java needs a main class having the “main” method implemented in it.
The first four classes are in the package named “com.tictactoe.components” , while the main class is in the package named “com.tictactoe”.
First we discuss the move class:
Move:
Move made by either of the players.
package com.tictactoe.components;
/**
*
* @author pratyush
*/
public class Move {
private int row, column;
private boolean isValid;
public int getRow() {
return row;
}
public void setRow(int row) {
this.row = row;
}
public int getColumn() {
return column;
}
public void setColumn(int column) {
this.column = column;
}
public boolean isIsValid() {
return isValid;
}
public void setIsValid(boolean isValid) {
this.isValid = isValid;
}
}
Then comes the Board class where the moves are made.
Board:
The board on which the game is played.
package com.tictactoe.components;
/**
*
* @author pratyush
*/
public class Board{
private static char[][] cells;
public Board()
{
cells = new char[3][3];
cells[0] = new char[]{' ', ' ', ' '};
cells[1] = new char[]{' ', ' ', ' '};
cells[2] = new char[]{' ', ' ', ' '};
}
public void display()
{
for(int i = 0; i < 3; i++)
{
for(int j = 0; j < 3; j++) {
if(cells[i][j] == ' ') {
System.out.print((i+1)+", "+(j+1)+"\t");
} else {
System.out.print(cells[i][j]+"\t");
}
} System.out.print("\n\n");
}
}
public Move checkAvailable(Move move) {
int i = move.getRow();
int j = move.getColumn();
boolean boundValid = ((i >= 1 && i<= 3) && ( j >= 1 && j <= 3));
boolean charValid = false;
if(boundValid)
{
charValid = (cells[i - 1][j - 1] == ' ');
}
boolean netValid = (boundValid && charValid);
move.setIsValid(netValid);
return move;
}
public void markCell(Move move, char mark)
{
if(move.isIsValid())
{
int i = move.getRow();
int j = move.getColumn();
cells[i - 1][j - 1] = mark;
}
else
{
System.out.println("INVALID MOVE!\n\n");
}
}
}
The Player class denotes the players who make moves on the board.
Player:
Either of the two players.
package com.tictactoe.components;
import java.util.ArrayList;
/**
*
* @author pratyush
*/
public class Player {
private int playerNum;
private char playerMark;
private int winnerOrLoser;
private Game g;
private ArrayList<Move> moves = new ArrayList<Move>();
public int getPlayerNum() {
return playerNum;
}
public void setPlayerNum(int playerNum) {
this.playerNum = playerNum;
}
public char getPlayerMark() {
return playerMark;
}
public void setPlayerMark(char playerMark) {
this.playerMark = playerMark;
}
public int getWinnerOrLoser() {
return winnerOrLoser;
}
public void setWinnerOrLoser(int winnerOrLoser) {
this.winnerOrLoser = winnerOrLoser;
}
public Game getGame() {
return g;
}
public void setGame(Game g) {
this.g = g;
}
public ArrayList getMoves() {
return moves;
}
public void addMove(Move move) {
this.moves.add(move);
}
public void makeMove(Board board, Move move)
{
move = board.checkAvailable(move);
char mark = this.getPlayerMark();
board.markCell(move, mark);
if(move.isIsValid())
{
this.addMove(move);
Game.setMovesTillNow();
}
board.display();
}
}
The Game class is the functionality of the game with all its rules.
Game:
The game being played.
package com.tictactoe.components;
import java.util.ArrayList;
/**
*
* @author pratyush
*/
public class Game{
private int whoseTurn;
private static int movesTillNow = 0;
private boolean gameOver;
private Player winner = null;
Move[][] winning_moves;
public Game()
{
winning_moves = new Move[8][3];
//top row
Move move01 = new Move();
move01.setRow(1);
move01.setColumn(1);
Move move02 = new Move();
move02.setRow(1);
move02.setColumn(2);
Move move03 = new Move();
move03.setRow(1);
move03.setColumn(3);
Move[] move0;
move0 = new Move[]{move01, move02, move03};
winning_moves[0] = move0;
//middle row
Move move11 = new Move();
move11.setRow(2);
move11.setColumn(1);
Move move12 = new Move();
move12.setRow(2);
move12.setColumn(2);
Move move13 = new Move();
move13.setRow(2);
move13.setColumn(3);
Move[] move1;
move1 = new Move[]{move11, move12, move13};
winning_moves[1] = move1;
//bottom row
Move move21 = new Move();
move21.setRow(3);
move21.setColumn(1);
Move move22 = new Move();
move22.setRow(3);
move22.setColumn(2);
Move move23 = new Move();
move23.setRow(3);
move23.setColumn(3);
Move[] move2;
move2 = new Move[]{move21, move22, move23};
winning_moves[2] = move2;
//column wise
//column 1
Move move31 = new Move();
move31.setRow(1);
move31.setColumn(1);
Move move32 = new Move();
move32.setRow(2);
move32.setColumn(1);
Move move33 = new Move();
move33.setRow(3);
move33.setColumn(1);
Move[] move3;
move3 = new Move[]{move31, move32, move33};
winning_moves[3] = move3;
//column 2
Move move41 = new Move();
move41.setRow(1);
move41.setColumn(2);
Move move42 = new Move();
move42.setRow(2);
move42.setColumn(2);
Move move43 = new Move();
move43.setRow(3);
move43.setColumn(2);
Move[] move4;
move4 = new Move[]{move41, move42, move43};
winning_moves[4] = move4;
//column 3
Move move51 = new Move();
move51.setRow(1);
move51.setColumn(3);
Move move52 = new Move();
move52.setRow(2);
move52.setColumn(3);
Move move53 = new Move();
move53.setRow(3);
move53.setColumn(3);
Move[] move5;
move5 = new Move[]{move51, move52, move53};
winning_moves[5] = move5;
//diagonals
//diagonal 1
Move move61 = new Move();
move61.setRow(1);
move61.setColumn(1);
Move move62 = new Move();
move62.setRow(2);
move62.setColumn(2);
Move move63 = new Move();
move63.setRow(3);
move63.setColumn(3);
Move[] move6;
move6 = new Move[]{move61, move62, move63};
winning_moves[6] = move6;
//diagonal 2
Move move71 = new Move();
move71.setRow(1);
move71.setColumn(3);
Move move72 = new Move();
move72.setRow(2);
move72.setColumn(2);
Move move73 = new Move();
move73.setRow(3);
move73.setColumn(1);
Move[] move7;
move7 = new Move[]{move71, move72, move73};
winning_moves[7] = move7;
}
public int getWhoseTurn() {
return whoseTurn;
}
public void setWhoseTurn(Player player) {
this.whoseTurn = player.getPlayerNum();
}
public static int getMovesTillNow() {
return movesTillNow;
}
public static void setMovesTillNow() {
Game.movesTillNow++;
}
public boolean isGameOver() {
return gameOver;
}
public void setGameOver(boolean gameOver) {
this.gameOver = gameOver;
}
public Player getWinner() {
return winner;
}
public void setWinner(Player winner) {
this.winner = winner;
}
private boolean checkSubset(Move[] subset, Move[] winning_row)
{
int count = 0;
for(int i = 0;i < 3; i++)
{
for(int j = 0; j< 3; j++)
{
if(subset[i].getRow() == winning_row[j].getRow() && subset[i].getColumn() == winning_row[j].getColumn())
{
count++;
}
}
}
return (count == 3);
}
//check the winning moves
public boolean checkWinningMoves(Player player)
{
/*****check winning moves*****/
int movesTillNow = Game.getMovesTillNow();
int whoseTurn = this.getWhoseTurn();
ArrayList<Move> playerMoves = player.getMoves();
int moves = movesTillNow;
Move[][] winning_moves1 = this.winning_moves;
switch(whoseTurn)
{
case 1:
if(moves < 5)
{
return false;
}
else
{
if(moves == 5)
{
Move[] player1_set1 = new Move[]{playerMoves.get(0), playerMoves.get(1), playerMoves.get(2)};
for(int i = 0; i< 8; i++)
{
if(checkSubset(player1_set1, winning_moves1[i]))
{
return true;
}
}
}
/******/
if(moves == 7)
{
Move[] player1_set2 = new Move[]{playerMoves.get(0), playerMoves.get(1), playerMoves.get(3)};
Move[] player1_set4 = new Move[]{playerMoves.get(0), playerMoves.get(2), playerMoves.get(3)};
Move[] player1_set7 = new Move[]{playerMoves.get(1), playerMoves.get(2), playerMoves.get(3)};
for(int i = 0; i < 8; i++)
{
if(checkSubset(player1_set2, winning_moves1[i]) ||
checkSubset(player1_set4, winning_moves1[i]) ||
checkSubset(player1_set7, winning_moves1[i]) )
{
return true;
}
}
}
if(moves == 9)
{
Move[] player1_set3 = new Move[]{playerMoves.get(0), playerMoves.get(1), playerMoves.get(4)};
Move[] player1_set5 = new Move[]{playerMoves.get(0), playerMoves.get(2), playerMoves.get(4)};
Move[] player1_set6 = new Move[]{playerMoves.get(0), playerMoves.get(3), playerMoves.get(4)};
Move[] player1_set8 = new Move[]{playerMoves.get(1), playerMoves.get(2), playerMoves.get(4)};
Move[] player1_set9 = new Move[]{playerMoves.get(1), playerMoves.get(3), playerMoves.get(4)};
Move[] player1_set10 = new Move[]{playerMoves.get(2), playerMoves.get(3), playerMoves.get(4)};
for(int i = 0; i < 8; i++)
{
if(checkSubset(player1_set3, winning_moves1[i]) ||
checkSubset(player1_set5, winning_moves1[i]) || checkSubset(player1_set6, winning_moves1[i]) ||
checkSubset(player1_set8, winning_moves1[i]) || checkSubset(player1_set9, winning_moves1[i]) ||
checkSubset(player1_set10, winning_moves1[i]))
{
return true;
}
}
}
return false;
}
case 2:
/******/
if(moves < 6)
{
return false;
}
else
{
/*******/
if(moves == 6)
{
Move[] player2_set1 = new Move[]{playerMoves.get(0), playerMoves.get(1), playerMoves.get(2)};
for(int i = 0; i < 8; i++)
{
if(checkSubset(player2_set1, winning_moves1[i]))
{
return true;
}
}
}
if(moves == 8)
{
Move[] player2_set2 = new Move[]{playerMoves.get(0), playerMoves.get(1), playerMoves.get(3)};
Move[] player2_set3 = new Move[]{playerMoves.get(0), playerMoves.get(2), playerMoves.get(3)};
Move[] player2_set4 = new Move[]{playerMoves.get(1), playerMoves.get(2), playerMoves.get(3)};
for(int i = 0; i < 8; i++)
{
if(checkSubset(player2_set2, winning_moves1[i]) || checkSubset(player2_set3, winning_moves1[i]) ||
checkSubset(player2_set4, winning_moves1[i]))
{
return true;
}
}
}
return false;
}
default:
return false;
}
}
}
Finally, the main class:
TicTacToe
The class containing the entry point of the program also called the main class.
package com.tictactoe;
import com.tictactoe.components.*;
import java.util.Scanner;
/**
*
* @author pratyush
*/
public class TicTacToe{
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
// TODO code application logic here
Game game = new Game();
Player player1 = new Player();
player1.setPlayerNum(1);
player1.setPlayerMark('X');
player1.setGame(game);
Player player2 = new Player();
player2.setPlayerNum(2);
player2.setPlayerMark('0');
player2.setGame(game);
Board board = new Board();
board.display();
/*******/
game.setWhoseTurn(player1);
game.setGameOver(false);
boolean status = game.isGameOver();
Scanner sc = new Scanner(System.in);
do
{
int movesNow = Game.getMovesTillNow();
if(movesNow == 9)
{
if(game.getWinner() == null)
{
System.out.println("TIE!\n");
break;
}
}
int turn = game.getWhoseTurn();
System.out.println("PLAYER "+turn+"\n");
int row = 0;
int column = 0;
boolean invalid = true;
while(invalid)
{
//code to handle invalid moves. players cannot proceed without valid input
try{
System.out.println("Enter row: ");
String str = sc.next();
if(!str.equals(""))
{
row = Integer.parseInt(str);
invalid = false;
}
else
{
continue;
}
}
catch(NumberFormatException n)
{
System.out.println("INVALID ROW!");
invalid = true;
}
catch(InputMismatchException i)
{
System.out.println("INVALID ROW!");
invalid = true;
}
}
invalid = true;
while(invalid)
{
/*code to handle invalid moves. players cannot proceed without valid input*/
try{
System.out.println("Enter column: ");
String str = sc.next();
if(!str.equals(""))
{
column = Integer.parseInt(str);
invalid = false;
}
else
{
continue;
}
}
catch(NumberFormatException n)
{
System.out.println("INVALID COLUMN!");
invalid = true;
}
catch(InputMismatchException i)
{
System.out.println("INVALID COLUMN!");
invalid = true;
}
}
/**/
Move move = new Move();
move.setRow(row);
move.setColumn(column);
switch(turn)
{
case 1:
player1.makeMove(board, move);
if(game.checkWinningMoves(player1))
{
game.setWinner(player1);
System.out.println("PLAYER 1 WINS!");
game.setGameOver(true);
}
else
{
if(move.isIsValid())
{
movesNow = Game.getMovesTillNow();
System.out.println("MOVE NUMBER "+movesNow+"\n");
game.setWhoseTurn(player2);
}
}
break;
case 2:
player2.makeMove(board, move);
if(game.checkWinningMoves(player2))
{
game.setWinner(player2);
System.out.println("PLAYER 2 WINS!");
game.setGameOver(true);
}
else
{
if(move.isIsValid())
{
movesNow = Game.getMovesTillNow();
System.out.println("MOVE NUMBER "+movesNow+"\n");
game.setWhoseTurn(player1);
}
}
break;
default:
System.out.println("ERROR!\n");
break;
}
status = game.isGameOver();
}
while(!status);
}
}
Copy, Compile, Run and ENJOY!
C# version
Here is an elementary tic-tac-toe or noughts and crosses game I made in C#, arguably the most popular language of the DotNET platform. It can be played from the command line after compiling it as an executable. In the game of tic-tac-toe there is a 3X3 grid or board.The game is for two players. The players 1 and 2 take turns to mark the cells of the grid with their mark which is a zero or a cross.
The first player to complete a vertical, horizontal or diagonal triad of zeroes or crosses, wins.
The PHP version can be found here
Player makes Move on Board to play Game. So the classes are:
- Move
- Board
- Player
- Game
- TicTacToe
There is one new class “TicTacToe” because C# needs a main class having the “Main” method implemented in it.
The classes are in the namespace called “TicTacToeDotNet”.
First we discuss the move class:
Move:
Move made by either of the players.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace TicTacToeDotNet
{
public class Move
{
private int row, column;
private bool isValid;
public int getRow()
{
return row;
}
public void setRow(int row)
{
this.row = row;
}
public int getColumn()
{
return column;
}
public void setColumn(int column)
{
this.column = column;
}
public bool isIsValid()
{
return isValid;
}
public void setIsValid(bool isValid)
{
this.isValid = isValid;
}
}
}
Then comes the Board class where the moves are made.
Board:
The board on which the game is played.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace TicTacToeDotNet
{
public class Board
{
private static char[][] cells;
public Board()
{
cells = new char[3][];
cells[0] = new char[] { ' ', ' ', ' ' };
cells[1] = new char[] { ' ', ' ', ' ' };
cells[2] = new char[] { ' ', ' ', ' ' };
}
public void display()
{
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 3; j++) {
if (cells[i][j] == ' ') {
Console.Write((i + 1) + ", " + (j + 1) + "\t");
} else {
Console.Write(cells[i][j] + "\t");
}
} Console.Write("\n\n");
}
}
public Move checkAvailable(Move move) {
int i = move.getRow();
int j = move.getColumn();
bool boundValid = ((i >= 1 && i <= 3) && (j >= 1 && j <= 3));
bool charValid = false;
if (boundValid)
{
charValid = (cells[i - 1][j - 1] == ' ');
}
bool netValid = (boundValid && charValid);
move.setIsValid(netValid);
return move;
}
public void markCell(Move move, char mark)
{
if (move.isIsValid())
{
int i = move.getRow();
int j = move.getColumn();
cells[i - 1][j - 1] = mark;
}
else
{
Console.Write("INVALID MOVE!\n\n");
}
}
}
}
The Player class denotes the players who make moves on the board.
Player:
Either of the two players.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace TicTacToeDotNet
{
public class Player
{
private int playerNum;
private char playerMark;
private int winnerOrLoser;
private Game g;
private List moves = new List();
public int getPlayerNum()
{
return playerNum;
}
public void setPlayerNum(int playerNum)
{
this.playerNum = playerNum;
}
public char getPlayerMark()
{
return playerMark;
}
public void setPlayerMark(char playerMark)
{
this.playerMark = playerMark;
}
public int getWinnerOrLoser()
{
return winnerOrLoser;
}
public void setWinnerOrLoser(int winnerOrLoser)
{
this.winnerOrLoser = winnerOrLoser;
}
public Game getGame()
{
return g;
}
public void setGame(Game g)
{
this.g = g;
}
public List getMoves()
{
return moves;
}
public void addMove(Move move)
{
this.moves.Add(move);
}
public void makeMove(Board board, Move move)
{
move = board.checkAvailable(move);
char mark = this.getPlayerMark();
board.markCell(move, mark);
if (move.isIsValid())
{
this.addMove(move);
Game.setMovesTillNow();
}
board.display();
}
}
}
The Game class is the functionality of the game with all its rules.
Game:
The game being played.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace TicTacToeDotNet
{
public class Game
{
private int whoseTurn;
private static int movesTillNow = 0;
private bool gameOver;
private Player winner = null;
Move[][] winning_moves;
public Game()
{
winning_moves = new Move[8][];
//top row
Move move01 = new Move();
move01.setRow(1);
move01.setColumn(1);
Move move02 = new Move();
move02.setRow(1);
move02.setColumn(2);
Move move03 = new Move();
move03.setRow(1);
move03.setColumn(3);
Move[] move0;
move0 = new Move[] { move01, move02, move03 };
winning_moves[0] = move0;
//middle row
Move move11 = new Move();
move11.setRow(2);
move11.setColumn(1);
Move move12 = new Move();
move12.setRow(2);
move12.setColumn(2);
Move move13 = new Move();
move13.setRow(2);
move13.setColumn(3);
Move[] move1;
move1 = new Move[] { move11, move12, move13 };
winning_moves[1] = move1;
//bottom row
Move move21 = new Move();
move21.setRow(3);
move21.setColumn(1);
Move move22 = new Move();
move22.setRow(3);
move22.setColumn(2);
Move move23 = new Move();
move23.setRow(3);
move23.setColumn(3);
Move[] move2;
move2 = new Move[] { move21, move22, move23 };
winning_moves[2] = move2;
//column wise
//column 1
Move move31 = new Move();
move31.setRow(1);
move31.setColumn(1);
Move move32 = new Move();
move32.setRow(2);
move32.setColumn(1);
Move move33 = new Move();
move33.setRow(3);
move33.setColumn(1);
Move[] move3;
move3 = new Move[] { move31, move32, move33 };
winning_moves[3] = move3;
//column 2
Move move41 = new Move();
move41.setRow(1);
move41.setColumn(2);
Move move42 = new Move();
move42.setRow(2);
move42.setColumn(2);
Move move43 = new Move();
move43.setRow(3);
move43.setColumn(2);
Move[] move4;
move4 = new Move[] { move41, move42, move43 };
winning_moves[4] = move4;
//column 3
Move move51 = new Move();
move51.setRow(1);
move51.setColumn(3);
Move move52 = new Move();
move52.setRow(2);
move52.setColumn(3);
Move move53 = new Move();
move53.setRow(3);
move53.setColumn(3);
Move[] move5;
move5 = new Move[] { move51, move52, move53 };
winning_moves[5] = move5;
//diagonals
//diagonal 1
Move move61 = new Move();
move61.setRow(1);
move61.setColumn(1);
Move move62 = new Move();
move62.setRow(2);
move62.setColumn(2);
Move move63 = new Move();
move63.setRow(3);
move63.setColumn(3);
Move[] move6;
move6 = new Move[] { move61, move62, move63 };
winning_moves[6] = move6;
//diagonal 2
Move move71 = new Move();
move71.setRow(1);
move71.setColumn(3);
Move move72 = new Move();
move72.setRow(2);
move72.setColumn(2);
Move move73 = new Move();
move73.setRow(3);
move73.setColumn(1);
Move[] move7;
move7 = new Move[] { move71, move72, move73 };
winning_moves[7] = move7;
}
public int getWhoseTurn()
{
return whoseTurn;
}
public void setWhoseTurn(Player player)
{
this.whoseTurn = player.getPlayerNum();
}
public static int getMovesTillNow()
{
return movesTillNow;
}
public static void setMovesTillNow()
{
Game.movesTillNow++;
}
public bool isGameOver()
{
return gameOver;
}
public void setGameOver(bool gameOver)
{
this.gameOver = gameOver;
}
public Player getWinner()
{
return winner;
}
public void setWinner(Player winner)
{
this.winner = winner;
}
private bool checkSubset(Move[] subset, Move[] winning_row)
{
int count = 0;
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 3; j++)
{
if (subset[i].getRow() == winning_row[j].getRow() && subset[i].getColumn() == winning_row[j].getColumn())
{
count++;
}
}
}
return (count == 3);
}
//check the winning moves
public bool checkWinningMoves(Player player)
{
/*****check winning moves*****/
int movesTillNow = Game.getMovesTillNow();
int whoseTurn = this.getWhoseTurn();
Move[] playerMoves = player.getMoves().ToArray();
int moves = movesTillNow;
Move[][] winning_moves1 = this.winning_moves;
switch (whoseTurn)
{
case 1:
if (moves < 5)
{
return false;
}
else
{
if (moves == 5)
{
Move[] player1_set1 = new Move[] { playerMoves[0], playerMoves[1], playerMoves[2] };
for (int i = 0; i < 8; i++)
{
if (checkSubset(player1_set1, winning_moves1[i]))
{
return true;
}
}
}
/******/
if (moves == 7)
{
Move[] player1_set2 = new Move[] { playerMoves[0], playerMoves[1], playerMoves[3] };
Move[] player1_set4 = new Move[] { playerMoves[0], playerMoves[2], playerMoves[3] };
Move[] player1_set7 = new Move[] { playerMoves[1], playerMoves[2], playerMoves[3] };
for (int i = 0; i < 8; i++)
{
if (checkSubset(player1_set2, winning_moves1[i]) ||
checkSubset(player1_set4, winning_moves1[i]) ||
checkSubset(player1_set7, winning_moves1[i]))
{
return true;
}
}
}
if (moves == 9)
{
Move[] player1_set3 = new Move[] { playerMoves[0], playerMoves[1], playerMoves[4] };
Move[] player1_set5 = new Move[] { playerMoves[0], playerMoves[2], playerMoves[4] };
Move[] player1_set6 = new Move[] { playerMoves[0], playerMoves[3], playerMoves[4] };
Move[] player1_set8 = new Move[] { playerMoves[1], playerMoves[2], playerMoves[4] };
Move[] player1_set9 = new Move[] { playerMoves[1], playerMoves[3], playerMoves[4] };
Move[] player1_set10 = new Move[] { playerMoves[2], playerMoves[3], playerMoves[4] };
for (int i = 0; i < 8; i++)
{
if (checkSubset(player1_set3, winning_moves1[i]) ||
checkSubset(player1_set5, winning_moves1[i]) || checkSubset(player1_set6, winning_moves1[i]) ||
checkSubset(player1_set8, winning_moves1[i]) || checkSubset(player1_set9, winning_moves1[i]) ||
checkSubset(player1_set10, winning_moves1[i]))
{
return true;
}
}
}
return false;
}
case 2:
/******/
if (moves < 6)
{
return false;
}
else
{
/*******/
if (moves == 6)
{
Move[] player2_set1 = new Move[] { playerMoves[0], playerMoves[1], playerMoves[2] };
for (int i = 0; i < 8; i++)
{
if (checkSubset(player2_set1, winning_moves1[i]))
{
return true;
}
}
}
if (moves == 8)
{
Move[] player2_set2 = new Move[] { playerMoves[0], playerMoves[1], playerMoves[3] };
Move[] player2_set3 = new Move[] { playerMoves[0], playerMoves[2], playerMoves[3] };
Move[] player2_set4 = new Move[] { playerMoves[1], playerMoves[2], playerMoves[3] };
for (int i = 0; i < 8; i++)
{
if (checkSubset(player2_set2, winning_moves1[i]) || checkSubset(player2_set3, winning_moves1[i]) ||
checkSubset(player2_set4, winning_moves1[i]))
{
return true;
}
}
}
return false;
}
default:
return false;
}
}
}
}
Finally, the main class:
TicTacToe
The class containing the entry point of the program also called the main class.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace TicTacToeDotNet
{
public class TicTacToe
{
/**
* @param args the command line arguments
*/
public static void Main(string[] args)
{
// TODO code application logic here
Game game = new Game();
Player player1 = new Player();
player1.setPlayerNum(1);
player1.setPlayerMark('X');
player1.setGame(game);
Player player2 = new Player();
player2.setPlayerNum(2);
player2.setPlayerMark('0');
player2.setGame(game);
Board board = new Board();
board.display();
/*******/
game.setWhoseTurn(player1);
game.setGameOver(false);
bool status = game.isGameOver();
//
do
{
int movesNow = Game.getMovesTillNow();
if (movesNow == 9)
{
if (game.getWinner() == null)
{
Console.WriteLine("TIE!\n");
break;
}
}
int turn = game.getWhoseTurn();
Console.WriteLine("PLAYER " + turn + "\n");
int row = 0;
int column = 0;
bool invalid = true;
while (invalid)
{
//code to handle invalid moves. players cannot proceed without valid input
try
{
Console.WriteLine("Enter row: ");
string str = Convert.ToString(Console.ReadLine());
if (!(str == ""))
{
row = Convert.ToInt32(str);
invalid = false;
}
else
{
continue;
}
}
catch (FormatException n)
{
Console.WriteLine("INVALID ROW!");
invalid = true;
}
/**/
}
invalid = true;
while (invalid)
{
/*code to handle invalid moves. players cannot proceed without valid input*/
try
{
Console.WriteLine("Enter column: ");
String str = Convert.ToString(Console.ReadLine());
if (!(str == ""))
{
column = Convert.ToInt32(str);
invalid = false;
}
else
{
continue;
}
}
catch (FormatException n)
{
Console.WriteLine("INVALID COLUMN!");
invalid = true;
}
/**/
}
/**/
Move move = new Move();
move.setRow(row);
move.setColumn(column);
switch (turn)
{
case 1:
player1.makeMove(board, move);
if (game.checkWinningMoves(player1))
{
game.setWinner(player1);
Console.WriteLine("PLAYER 1 WINS!");
game.setGameOver(true);
}
else
{
if (move.isIsValid())
{
movesNow = Game.getMovesTillNow();
Console.WriteLine("MOVE NUMBER " + movesNow + "\n");
game.setWhoseTurn(player2);
}
}
break;
case 2:
player2.makeMove(board, move);
if (game.checkWinningMoves(player2))
{
game.setWinner(player2);
Console.WriteLine("PLAYER 2 WINS!");
game.setGameOver(true);
}
else
{
if (move.isIsValid())
{
movesNow = Game.getMovesTillNow();
Console.WriteLine("MOVE NUMBER " + movesNow + "\n");
game.setWhoseTurn(player1);
}
}
break;
default:
Console.WriteLine("ERROR!\n");
break;
}
status = game.isGameOver();
}
while (!status);
Console.Read();
}
}
}
Copy, Compile, Run and ENJOY!