The below code works as expected, however I would like to simplify the method as it is currently too repetitive. My hopes in simplifying the code would be to develop a means to enhance the AI. I would have the AI check for patterns on the board and have it act accordingly.
public boolean checkWinner(){
//CHECK EVERY POSSIBLE WINNING OUTCOME and return true if you find one
//don't forget to check if the board is full (return true in that case)
if(gameboard[0] == gameboard[1] && gameboard[1] == gameboard[2] ||
gameboard[3] == gameboard[4] && gameboard[4] == gameboard[5] ||
gameboard[6] == gameboard[7] && gameboard[7] == gameboard[8] ||
gameboard[0] == gameboard[3] && gameboard[3] == gameboard[6] ||
gameboard[1] == gameboard[4] && gameboard[4] == gameboard[7] ||
gameboard[2] == gameboard[5] && gameboard[5] == gameboard[8] ||
gameboard[0] == gameboard[4] && gameboard[4] == gameboard[8] ||
gameboard[6] == gameboard[4] && gameboard[4] == gameboard[2] ){
bigWinner();
return true;
}
//loop through and look for tie
for(int x = 0; x< gameboard.length; x++){
if(gameboard[x] != 'O' && gameboard[x] != 'X'){
return false;
}
}
System.out.println("Tie Game.");
return true;
}
The full code of the TicTacToe class is as follows. The Main class of the game displays a game menu and creates a new TicTacToe game.
package pkg2baresb;
import java.util.Scanner;
import java.util.concurrent.ThreadLocalRandom;
/**
* This is the game logic for TicTacToe
* @author baresb
*/
public class TicTacToe {
//ENCAPUSLATED game variables. Super secret!
private char[] gameboard;
private boolean myTurn = true;
/**
* The TicTacToe's constructor
*/
public TicTacToe(){
//instantiate the previous declared value
gameboard = new char[9];
final int RADIX = 10;
//loop through game array and start each spot with a dash
for(int x = 0; x < gameboard.length; x++){
gameboard[x] = Character.forDigit(x, RADIX);
}
System.out.println("TICTACTOE ONLINE.");
//Loop until there's a winner
while(!checkWinner()){
printBoard();
yourTurn();
}
printBoard();
if(!checkWinner()) yourTurn();
else{
System.out.println("Game over.");
}
}
/**
*
* @return
*/
public boolean checkWinner(){
//CHECK EVERY POSSIBLE WINNING OUTCOME and return true if you find one
//don't forget to check if the board is full (return true in that case)
if(gameboard[0] == gameboard[1] && gameboard[1] == gameboard[2] ||
gameboard[3] == gameboard[4] && gameboard[4] == gameboard[5] ||
gameboard[6] == gameboard[7] && gameboard[7] == gameboard[8] ||
gameboard[0] == gameboard[3] && gameboard[3] == gameboard[6] ||
gameboard[1] == gameboard[4] && gameboard[4] == gameboard[7] ||
gameboard[2] == gameboard[5] && gameboard[5] == gameboard[8] ||
gameboard[0] == gameboard[4] && gameboard[4] == gameboard[8] ||
gameboard[6] == gameboard[4] && gameboard[4] == gameboard[2] ){
bigWinner();
return true;
}
//loop through and look for tie
for(int x = 0; x< gameboard.length; x++){
if(gameboard[x] != 'O' && gameboard[x] != 'X'){
return false;
}
}
System.out.println("Tie Game.");
return true;
}
/**
* Use a scanner and take an input from the user
*/
public void yourTurn(){
//instantiate a Scanner
Scanner s = new Scanner(System.in);
//take an input on the position the player would like
int selection;
while(true){
try{
System.out.print("What position would you like to play: ");
selection = s.nextInt();
if(gameboard[selection] != 'X' && gameboard[selection] != 'O'){
gameboard[selection] = 'X';
break;
}else{
System.out.println("That spot has already been taken");
}
}catch(Exception e){
System.out.println("Invalid selection. Please try again.");
}
}
if(!checkWinner()) {
this.myTurn = !myTurn;
//hands things over to the computer
computersTurn();
}
}
/**
* Announce who won using the myTurn boolean to remember whose turn it was
* last
*/
public void bigWinner(){
if(myTurn){
System.out.println("You won! Nice job!");
}else{
System.out.println("You have lost the game.");
}
}
/**
* Computer selects a random open slot and play its 'O'
*/
public void computersTurn(){
//OPTIONAL: MAKE THIS CODE SMARTER
System.out.println("Now it's the computer player's turn");
while(true){
//generate a random number between 0 - 8
int choice = ThreadLocalRandom.current().nextInt(0, 9);
//is the space free?
if(gameboard[choice] != 'X' && gameboard[choice] != 'O') {
//if so, set it equal to an 'O'
gameboard[choice] = 'O';
//bust out of this while loop
this.myTurn = !myTurn;
break;
}
} //closes while loop
} //closes computersTurn
public void printBoard(){
for(int x = 1; x <= gameboard.length; x++){
System.out.print(" | " + gameboard[x-1]);
if(x % 3 == 0) System.out.println(" |");
}
}
}
To make your code less repetitive. You could create a method that takes a game board and a matrix as a parameter:
public boolean checkWin(int[] gameBoard, int[][] winPossibilities) {
}
winPossibilities
is all the rows/columns/diagonals that you want to check. In your case, it would be
final int[][] possibilities = {
{0, 1, 2},
{3, 4, 5},
{6, 7, 8},
{0, 3, 6},
{1, 4, 7},
{2, 5, 8},
{0, 4, 8},
{6, 4, 2},
};
In the body of the method, you just need a simple algorithm like this:
for (int[] indices: winPossibilities) {
if (gameBoard[i[0]] == gameBoard[i[1]] && gameBoard[i[1]] == gameBoard[i[2]]) {
return true;
}
}
return false;
You can call this method like this:
if(checkWin(gameboard, possibilities)){
bigWinner();
return true;
}
//loop through and look for tie
for(int x = 0; x< gameboard.length; x++){
if(gameboard[x] != 'O' && gameboard[x] != 'X'){
return false;
}
}
System.out.println("Tie Game.");
return true;
One of the benefits that this provides is more flexibility. If you want to change the rules of tic tac toe and decides that you can't win by making a diagonal, just remove the last two items of the possibilities
matrix!