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!