Hello, I have been self-teaching myself Java for the past few weeks and I would like a little help. Without an instructor or ample code snippets that are readable to me, I've been finding it difficult to know if my coding lacks the polish and efficiency necessary.

Here is the completed code of my Tic Tac Toe game:
I would love it if someone took a look at the AI especially, and possibly suggest an altrenate, more efficient algorithm. Otherwise, any comments would be appreciated.

Classes are:
1.)TicTacToeGame
2.)Game
3.)Player
4.)Input (which contains only static members)

Thanks in advance for any critique I recieve...

import java.io.*;

public class TicTacToeGame
{
	public static void main(String[] args)
	{
		Game newGame=new Game();
		newGame.start();
	}
}

class Game
{
	String[][] board = { {" ", " ", " "}, {" ", " ", " "}, {" ", " ", " "} }; //new String[3][3];
	
	void start()
	{
		do
		{
			for (int c=0; c < 3; c++)
			{
				for (int f=0; f < 3; f++)
				{
					board[c][f]=" ";
				}
			}
			play();
		}
		while ( playAgainQuery() );
	}
	
	void play()
	{
		Player p1 = new Player("X", false);
		Player p2 = new Player("O", true);
		String winner="Draw";
		boolean playing=true;
		
		System.out.println ("Let's play Tic Tac Toe!");
		p2.chooseCPU();
		printBoard();
		while(playing)
		{
			p1.getInput(board);
			board[p1.x-1][p1.y-1]=p1.mark;
			System.out.println("Player " + p1.mark + " places at location: (" + p1.x + "," + p1.y + ")");
			printBoard();
			if ((winner = checkVictory() ) != "None")
			{
				playing=false;
				break;
			} // end of Victory check IF
			p2.getInput(board);
			board[p2.x-1][p2.y-1]=p2.mark;
			System.out.println("Player " + p2.mark + " places at location: (" + p2.x + "," + p2.y + ")");
			printBoard();
			if ((winner = checkVictory() ) != "None")
			{
				playing=false;
				break;
			} // end of Victory check IF
		} // end of main game loop
		if (winner == "Draw")
		{
			System.out.println("The game was a draw!");
		}
		else
		{
			System.out.println("Player " + winner + " wins the game!");
		}
	} // end of method Play
	
	String checkVictory()
	{
		String winner = "Draw";
		for (int i=0; i < 3; i++)
		{	
			for (int l=0; l < 3; l++)
			{
				if (board[i][l] == " ")
				{
					winner = "None";
					break;
				}
			}
			if ( (board[i][0]==board[i][1]) && (board[i][1] == board[i][2]) && (board[i][0] != " ") )
			{
				winner=board[i][0];
				break;
			}
			
		} // END OF FIRST FOR
		
		if ( (winner != "None") || (winner != "Draw") )
		{
			for (int i=0; i < 3; i++)
			{
				if ( (board[0][i]==board[1][i]) && (board[1][i] == board[2][i]) && (board[0][i] != " ") )
				{
					winner=board[0][i];
				}
			} // end second For loop
			if ( (board[0][0]==board[1][1]) && (board[1][1] == board[2][2]) && (board[0][0] != " ") )
			{
					winner=board[0][0];
			} // diagonal one
			if ( (board[0][2]==board[1][1]) && (board[1][1] == board[2][0]) && (board[0][2] != " ") )
			{
					winner=board[0][2];
			} // diagonal two
		} // end if for first For loop
		return winner;
	}
	
	void printBoard()
	{
		for (int i=0; i < 3; i++)
		{
			for (int l=0; l < 3; l++)
			{
				System.out.print(board[l][i]);
				if (l != 2)
				{
					System.out.print(" | ");
				}
			}
			if (i != 2)
			{
				System.out.println("\n---------");
			}
		}
		System.out.println("\n");
	} // end of printBoard()
	
	boolean playAgainQuery()
	{
		int choice=0;			
		while ( (choice != 2) & (choice != 1) )
		{
			System.out.print ("Play Again? Yes(1)/No(2): ");
			choice = Input.getInt();
			System.out.println(" ");
			if (Input.ERROR)
			{
				System.out.println("Uniterpretable input.");
				Input.reset();
			}
			if ( (choice != 2) & (choice != 1) )
			{
				System.out.println("Please enter a 1(Yes) or a 2(No).");
				System.out.println(" ");
			}
		} // end of while loop		
		if ( choice == 1  )
		{
			System.out.println(" ");
			return (true);
		}
		if ( choice == 2 )
		{
			System.out.println ("Play Again Soon!");
			return (false);
		}
		return (false);
	} // end of playAgainQuery()
}

class Player
{
	String mark;
	boolean CPU;
	int x, y;
	
	public Player()
	{
		mark="X";
		CPU=false;
		x=0;
		y=0;
	}
	
	public Player(String marker, boolean CP)
	{
		mark=marker;
		CPU=CP;
		x=0;
		y=0;
	}
	
	public Player(boolean CP, String marker)
	{
		mark=marker;
		CPU=CP;
		x=0;
		y=0;
	}
	
	public void chooseCPU()
	{
		String inputLine = null;
		int choice=0;
		do
		{
			System.out.print ("Play Singleplayer(1) or Multiplayer(2): ");
			choice = Input.getInt();
			System.out.println(" ");
			if (Input.ERROR)
			{
				System.out.println("Uniterpretable input.");
				Input.reset();
			}
			if ( (choice != 2) & (choice != 1) )
			{
				System.out.println("Please enter a 1(Singleplayer) or a 2(Multiplayer).");
				System.out.println(" ");
			}			
		}
		while ( (choice != 1) && (choice != 2) );
		if (choice == 1)
		{
			CPU=true;
			System.out.println("Battle against the computer in singleplayer!");
		}
		if (choice == 2)
		{
			CPU=false;
			System.out.println("Battle head to head in multiplayer!");
		}
	} // end of chooseCPU
	
	private boolean blocking (String[][] board)
	{
		boolean block = false;
		x=0;
		y=0;
		for (int i=0; i < 3; i++)
		{
			if ( (board[i][0] == board[i][1]) && (board[i][0] != " ") && (board[i][2] == " ") )
			{
				x=i+1;
				y=3;
				block=true;
				if (board[i][0] == mark) // be sure to break out if there is a winning opportunity
				{
					return true;
				}
			}
			if ( (board[i][1] == board[i][2]) && (board[i][1] != " ") && (board[i][0] == " ") )
			{
				x=i+1;
				y=1;
				block=true;
				if (board[i][1] == mark)
				{
					return true;
				}
			}
			if ( (board[i][0] == board[i][2]) && (board[i][0] != " ") && (board[i][1] == " ") )
			{
				x=i+1;
				y=2;
				block=true;
				if (board[i][0] == mark)
				{
					return true;
				}
			} // end of first series of if statements
			
			
			
			if ( (board[0][i] == board[1][i]) && (board[0][i] != " ") && (board[2][i] == " ") )
			{
				x=3;
				y=i+1;
				block=true;
				if (board[0][i] == mark)
				{
					return true;
				}
			}
			if ( (board[1][i] == board[2][i]) && (board[1][i] != " ") && (board[0][i] == " ") )
			{
				x=1;
				y=i+1;
				block=true;
				if (board[1][i] == mark)
				{
					return true;
				}
			}
			if ( (board[0][i] == board[2][i]) && (board[0][i] != " ") && (board[1][i] == " ") )
			{
				x=2;
				y=i+1;
				block=true;
				if (board[0][i] == mark)
				{
					return true;
				}
			} // end of second series of if statements
		} // end of first for loop for vertical and horizontal
		
		if ( (board[0][0] == board[2][2]) && (board[0][0] != " ") && (board[1][1] == " ") )
		{
			x=2;
			y=2;
			block=true;
			if (board[0][0] == mark)
			{
				return true;
			}
		}
		if ( (board[0][0] == board[1][1]) && (board[0][0] != " ") && (board[2][2] == " ") )
		{
			x=3;
			y=3;
			block=true;
			if (board[0][0] == mark)
			{
				return true;
			}
		}
		if ( (board[1][1] == board[2][2]) && (board[1][1] != " ") && (board[0][0] == " ") )
		{
			x=1;
			y=1;
			block=true;
			if (board[1][1] == mark)
			{
				return true;
			}
		} // end of first diagonal ifs
		
		if ( (board[0][2] == board[2][0]) && (board[0][2] != " ") && (board[1][1] == " ") )
		{
			x=2;
			y=2;
			block=true;
			if (board[0][2] == mark)
			{
				return true;
			}
		}
		if ( (board[0][2] == board[1][1]) && (board[0][2] != " ") && (board[2][0] == " ") )
		{
			x=3;
			y=1;
			block=true;
			if (board[0][2] == mark)
			{
				return true;
			}
		}
		if ( (board[1][1] == board[2][0]) && (board[1][1] != " ") && (board[0][2] == " ") )
		{
			x=1;
			y=3;
			block=true;
			if (board[1][1] == mark)
			{
				return true;
			}
		} // end of second diagonal ifs
		
		//System.out.println("Blocking state: " + block);
		//System.out.println("X: "+ x + "  Y: " + y);
		return block;
	} // end of blocking procedure
	
	public void getInput(String[][] board)
	{
		if (CPU == true)
		{
			if (blocking(board) == false)
			{
				do
				{
					x= (int) ( Math.random()*3 ) + 1;
					y= (int) ( Math.random()*3 ) + 1;
					
				}
				while ( (board[x-1][y-1] == "X") || (board[x-1][y-1] == "O") );
			}
		}
		else
		{
			getUserInput(board);
		}
	} // end of GetInput
	
	private void getUserInput(String[][] board)
	{
		x=0;
		y=0;
		boolean done=true;
		do
		{
			done=true;
			Input.reset();
			System.out.print ("Enter the X value to place your " + mark + " in: ");
			x = Input.getInt();
			System.out.print ("Enter the Y value to place your " + mark + " in: ");
			y = Input.getInt();
			System.out.println(" ");
			if (Input.ERROR)
			{
				System.out.println("Uninterpretable input.  Please enter again.");
				System.out.println(" ");
				done=false;
			}
			if (done)
			{
				if ( ( (x<1) || (x>3) ) || ( (y<1) || (y>3) ) )
				{
					System.out.println("X or Y is too large or small.  Please enter again using numbers 1-3.");
					System.out.println(" ");
					done=false;
				}
			}
			if (done)
			{
				if ( (board[x-1][y-1] == "X") || (board[x-1][y-1] == "O") )
				{
					System.out.println("Spot already occupied.  Please enter again.");
					System.out.println(" ");
					done=false;
				}
			}
		}
		while (!done);
		Input.reset();
	}//end of GetUserInput
} // end of class Player

class Input
{
	static boolean ERROR;
	
	static
	{
		ERROR=false;
	}
	
	public static int getInt()
	{
		int ret=-10;
		try
		{
			String inputLine = null;
			BufferedReader is = new BufferedReader(new InputStreamReader(System.in) );
			inputLine=is.readLine();
			ret = Integer.parseInt(inputLine);
		}
		catch (Exception ex)
		{
			ret = -10;
			ERROR=true;
		}
		finally
		{
			return ret;
		}
	}
	
	public static void reset()
	{
		ERROR=false;
	}
}

Recommended Answers

All 2 Replies

Issues that I see:
1) Logic is hard-coded to 3x3 board. Array positions, bounds checks, adjacency checks are using literals in many places.
2) Heavy repetition of if() blocks that are nearly identical, especially in the blocking() method. These could probably be replaced with a parameterized method or by adding a second array dimension loop and converting the checks to use relative indexes instead of the hard-coded positions.

The code is certainly not awful, just a little bit raw and literal. These are just things you might want to think on if you want to handle the logic a little more abstractly. Take a step back from a fixed 3x3 board and consider the nature of the operations you need to perform in terms of relative positions within a square grid. Also moving some operations into clearly named methods, which can help with clarity and organization in addition to limiting repetition.

Thank you for your helpful response, I'll start working on those changes.

Does anyone happen to know of any good sources that teach/demonstrate good OO design? That would be appreciated.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.