PDA

View Full Version : help with arrays


mdnealy
12-09-2009, 06:13 PM
I have completed part of my tic tac toe program. If you can look at the code and tell me what i am doing wrong I would appreciate it. I am working on the board and passing it to the test.

public class TicTacToeBoard {
private String [][] board;

public TicTacToeBoard(String[][]boardArray){
board=boardArray;}


public void displayBoard()
{
System.out.println(" | | ");
System.out.println("--------");
System.out.println(" | | ");
System.out.println("--------");
System.out.println(" | | ");
}

}

and the board passes to the test..but i have errors..

import java.util.Scanner;


public class TicTacToeTest {


public static void main(String[] args) {

TicTacToeBoard board = new TicTacToeBoard(board);

System.out.println("Main Menu\n WELCOME TO TIC-TAC-TOE!");
System.out.println();
System.out.println("1. One player game.\n2. Two player game.");
Scanner input= new Scanner(System.in);

System.out.print("Please Select: ");
int game= input.nextInt();
System.out.printf("selection=%d", game);
if ( game==1){
System.out.println("One Player Game\nWho will go first?\n1. Me.\n2. The Computer.");
System.out.print("Please Select: ");
int choice= input.nextInt();
System.out.printf("selection=%d", choice);}
else {
System.out.println("Two Player Game");
System.out.print("Please enter first players name:\n");
String player1=input.next();

System.out.print("Please enter Second players name:");
String player2=input.next();
System.out.printf("second player=%s\n",player1);
System.out.printf("first player=%s\n",player1);}
}
board.displayBoard();

}

thanks for your help

shadowmaniac
12-09-2009, 06:24 PM
TicTacToeBoard board = new TicTacToeBoard(board);

makes no sense.

Next time, tell us what error message(s) you're getting.

mdnealy
12-09-2009, 06:34 PM
the error is in the test.. the highlighted is underlined.

TicTacToeBoard board = new TicTacToeBoard(board);

and if this doesn't make sense...could you please explain why. dont i have to do an instance of board so i can execute it through the test?

Fou-Lu
12-09-2009, 07:05 PM
Board is not defined as a string[][] at this point in time.
I'd suggest actually writing a default constructor for the TicTacToeBoard class:

public TicTacToeBoard()
{
String[][] s = {{" ", " ", " "}, {" ", " ", " "}, {" ", " ", " "}};
this(s);
}

This will prevent it from tossing an error, and let you use just new TicTacToeBoard() without a given board.
Then in display board, you follow the same basic idea, but you loop you're array to display it (I can't test this atm, sorry):

public String displayBoard()
{
StringBuilder sbResult = new StringBuilder();
for (int i = 0; i < this.board.length; ++i)
{
for (int j = 0; j < this.board[i].length; ++j)
{
if (j > 0)
{
sbResult.append(" |");
}
sbResult.append(" " + this.board[i][j]);
}
sbResult.append("-----------\n");
}

return sbResult.toString();
}



Also, running you're code through the cli compilier will actually tell you what the problem is, in this case its probably complaining about unknown symbol board with a little arrow pointing to it. Most IDE's will also have an output for this, visual studio has theirs in the errors tab (not for java obviously), eclipse has a console tab I believe is what its called. Always post that if you're experiencing a particular compilation error - sometimes its not what it seems.

Old Pedant
12-09-2009, 08:43 PM
But see my answer to your question about enum.

You don't WANT to use String as the base type of your board array.

(Well, YOU may want to, but it looks like the instructor doesn't want you to. <grin/>)

mdnealy
12-10-2009, 09:41 AM
I did fix that part. i created an enum..and changed the board. can you look at my board code and see what you think..//. THE ARRAY IS HERE. I SET THE BOARD TO EMPTY SO
//THAT WHEN A PLAYER MAKES A MOVE IF IT IS E THEN THEY CAN REPLACE IT WITH AND X OR O.
// I THEN DID A METHOD THAT WHEN PLAYER 1 WHICH WILL BE X AND HUMAN IT WOULD PLACE AN X IN THE BOARD...PLAYER TWO H
//HUMAN OR COMPUTER WILL PLACE AN O. AGAIN I HAVEN'T ASSIGNED THE PLAYER TO X OR O YET. COULD YOU LOOK AT THIS
// AND LET ME KNOW SOME OF MY QUESTIONS.



import java.util.Arrays;

public class TicTacToeBoard
{
private TicTacToeEnum[][] moves;

public TicTacToeBoard(){
moves= new TicTacToeEnum[3][3];
}
//I AM NOT SURE WHY THE MOVES.ADD(MOVE); IS ERRORING...
public void addMoves(TicTacToeEnum move){
moves.add(move);
}

{ // I DID THIS TO SET MY BOARD TO EMPTY
TicTacToeEnum[][] letter= new TicTacToeEnum[3][3];
letter[0][0]= TicTacToeEnum.E;
letter[0][1]= TicTacToeEnum.E;
letter[0][2]= TicTacToeEnum.E;
letter[1][0]= TicTacToeEnum.E;
letter[1][1]= TicTacToeEnum.E;
letter[1][2]= TicTacToeEnum.E;
letter[2][0]= TicTacToeEnum.E;
letter[2][1]= TicTacToeEnum.E;
letter[2][2]= TicTacToeEnum.E;
//I LOOPED SO THAT WHEN I DO GET A VALUE IT WILL GO ROW= I AND COLUMN = J DO
// I NEED TO PRINT EACH OUT SEPARATE? I AM NOT SURE WHY IT IS NOT READING THE [I][J]
for(int i=0;i<letter.length;i++);
for(int j = 0; j< letter.length;j++);
{System.out.printf("%s",getValue(letter[i][j]));}

//I DID THIS SO THAT IT WILL KNOW TO PUT IN THE STRING.. I HAVENT ATTACHED TO THE PLAYER YET..
public static String getValue(TicTacToeEnum move)
{
String letterDescription = "";
if (move==TicTacToeEnum.X){
letterDescription = "X";
}
else
if (move==TicTacToeEnum.O){
letterDescription = "O";
}
return letterDescription;
}
}




thanks so much for your help

Old Pedant
12-10-2009, 06:29 PM
So that, eventually, you can play several games without having to restart the program each time, I'd put the board-clearing code (that is, setting all cells to empty) into a method, so you can call it as needed.

And I'd use a switch in getValue, thus:

public static String getValue(TicTacToeEnum move)
{
switch ( move )
{
case TicTacToeEnum.X: return "X";
case TicTacToeEnum.Y: return "Y";
case else: return " ";
}
}

There's actually a much more elegant way to do this, using mildly advanced coding for the enum, but this is a start.

Old Pedant
12-10-2009, 06:45 PM
OOPS...your board printing code is flawed! You can *NOT* put ; after the for!

Also, you REALLY should *ALWAYS* use {...}


for(int i=0;i<letter.length;i++)
{
for(int j = 0; j< letter[i].length;j++)
{
System.out.printf("%s",getValue(letter[i][j]));
}
}

But that will print an ugly board. You should rethink it.

Fou-Lu
12-10-2009, 07:19 PM
Technically you can have the ; in a for or while. Its just that its evaluated as true once where it then breaks - so logically this kinda defeats the purpose of the loop :P

Look at my suggestion for the display, although untested it looks nice in my head :)
You'll need to modify it a bit to handle the enum to char display, but I suspect it will work.

Also, as old pendant mentioned, I would always use the {} around block statements even where optional (such as a one line if or for statement). This isn't embedded device code we're talking about, so taking a minor blow on optimization for readability is much better - not to mention that the compiler may take care of optimizing that anyway.

All and all, this is getting there. Soon you'll be able to integrate the actual play method where it determines if a line is owned by a particular player for the win. A little more work with a standard 2D array, but certainly doable.

Old Pedant
12-10-2009, 07:39 PM
Fou-Lu caught me: I was sloppy in saying you can't put the semicolon there. You can. It just won't do what you think it will, then.

Fou-Lu: When compiled to byte-code (long before even the conversion to machine code) there is no difference between source with { } and source without it (assuming that it's a single statement enclosed in the braces, of course). That's not even an optimization: The "extra" braces are just syntactic sugar and have no impact on the semantics, so by definition the compiled code *should* be identical.

mdnealy
12-11-2009, 03:46 PM
I am really missing something here. I have moved the code around and around and I can get a print out of X, O in a straight line up and down. I need the board to look like this..

|__|__|__|
|__|__|__|
|__|__|__| with the x's and o's going inside. do I make another 2 dimensional array so that i can put the other array inside...

here is what i have on my board class, remember I have
other classes in my program for test, player, computer player, and enum...

I am not trying to be dumb but it seems to be happening on its own...

public class TicTacToeBoard
{
private TicTacToeEnum[][] board;
public TicTacToeBoard(){
board=new TicTacToeEnum[3][3];
{

//TicTacToeEnum[][] board;{
{{board[0][0]= TicTacToeEnum.X;board[0][1]= TicTacToeEnum.X; board[0][2]= TicTacToeEnum.X; }
{board[1][0]= TicTacToeEnum.O;board[1][1]= TicTacToeEnum.X;board[1][2]= TicTacToeEnum.X;}
{board[2][0]= TicTacToeEnum.O; board[2][1]= TicTacToeEnum.X;board[2][2]= TicTacToeEnum.X;} }}}

// public void addMoves(TicTacToeEnum move){

public void printBoard()
{

for(int row =0;row<board.length;row++)
{
for(int column = 0; column< board[ row ].length;column++)
{
System.out.printf("%s\n",getValue(board[ row ][column]));}}

}


public static String getValue(TicTacToeEnum board)
{
String letterDescription = "";
if (board==TicTacToeEnum.X){
letterDescription = "X";
}
else
if (board==TicTacToeEnum.O){
letterDescription = "O";
}
return letterDescription;
}



}


here is my test in case it is needed
import java.util.Scanner;


public class TicTacToeTest {


public static void main(String[] args) {

System.out.println("Main Menu\n WELCOME TO TIC-TAC-TOE!");
System.out.println();
System.out.println("1. One player game.\n2. Two player game.");
Scanner input= new Scanner(System.in);

System.out.print("Please Select: ");
int game= input.nextInt();
System.out.printf("selection=%d", game);
if ( game==1){
System.out.println("One Player Game\nWho will go first?\n1. Me.\n2. The Computer.");
System.out.print("Please Select: ");
int choice= input.nextInt();
System.out.printf("selection=%d", choice);}
else {
System.out.println("Two Player Game");
HumanPlayer hp= new HumanPlayer(null, null);
hp.getFirstPlayer();
hp.getSecondPlayer();
TicTacToeBoard bd = new TicTacToeBoard();
bd.printBoard();

}







}
}


and of course the enum
public enum TicTacToeEnum {
X
,O
,Empty
}

Old Pedant
12-11-2009, 06:30 PM
No no no...you do *not* need another array.

You just need a smarter board printer. Or, actually, a dumber one.

Don't try to finesse it. Just use brute force:

0,0 | 0,1 | 0,2
--------------
1,0 | 1,1 | 1,2
--------------
2,0 | 2,1 | 2,2

where here the r,c notation means "print the string value of the cell with those coordinates".

Try this:

Add a showRow(rownumber) method and then have showBoard just do:

showRow(0);
showLine();
showRow(1);
showLine();
showRow(2);

Old Pedant
12-11-2009, 06:53 PM
What the heck:


String rowToText(row)
{
return getValue(letter[row][0]) + "|"
+ getValue(letter[row][1]) + "|"
+ getValue(letter[row][0]);
}
void showBoard( )
{
System.out.println(rowToText(0));
System.out.println("-----");
System.out.println(rowToText(1));
System.out.println("-----");
System.out.println(rowToText(2));
}

See? K.I.S.S.

There are times to use loops and there are times NOT to use them. This is a time NOT to.

I'm curious why you chose the name "letter" instead of "board". The latter is more descriptive. And empty cell doesn't contain a letter. And, on top of that, because you are using an enum, none of the cells *actually* contain a letter, at all.

mdnealy
12-11-2009, 06:57 PM
do i make this:
Code:
0,0 | 0,1 | 0,2
--------------
1,0 | 1,1 | 1,2
--------------
2,0 | 2,1 | 2,2

a method? when i put the second code you had in the only error was

(rownumber)

I guess i don't understand where in my code do you put this..

mdnealy
12-11-2009, 07:20 PM
okay, your last post getting rid of the loop worked great...I changed letter back to board because what i did didn't make sense...just got confusted. okay now i am on to getting the inputs from players and validating....Please keep an eye out for me...I am on my way :) thanks so much!!!

mdnealy
12-11-2009, 08:57 PM
board[0][0]= TicTacToeEnum.Empty;
board[0][1]= TicTacToeEnum.Empty;
board[0][2]= TicTacToeEnum.Empty;
board[1][0]= TicTacToeEnum.Empty;
board[1][1]= TicTacToeEnum.Empty;
board[1][2]= TicTacToeEnum.Empty;
board[2][0]= TicTacToeEnum.Empty;
board[2][1]= TicTacToeEnum.Empty;
board[2][2]= TicTacToeEnum.Empty;}}





here is the humanPlayer class..
import java.util.Scanner;


public class HumanPlayer {

private String firstPlayer ;
private String secondPlayer;
private int row ;
private int column;
TicTacToeBoard bd = new TicTacToeBoard();

public HumanPlayer(String Player1, String Player2){
setFirstPlayer(Player1);
setSecondPlayer(Player2);
}




Scanner input = new Scanner(System.in);
public void setFirstPlayer(String firstPlayer) {
this.firstPlayer = firstPlayer;
}
public String getFirstPlayer() {
System.out.print("please enter Player 1 name:");
firstPlayer= input.next();
return firstPlayer;
}

public void setSecondPlayer(String secondPlayer) {
this.secondPlayer = secondPlayer;
}
public String getSecondPlayer() {
System.out.print("Please enter Player 2 name:");
secondPlayer=input.next();
return secondPlayer;
}

public void getMove(){
System.out.print( firstPlayer +" Enter row:" );
int row = input.nextInt();
System.out.print( firstPlayer +" Enter column:");
column = input.nextInt();

//Store row and column to board

}

}


public void setRow(int row) {
this.row = row;
}
public int getRow() {
return row= bd.rowToText(row);
}
public void setColumn(int column) {
this.column = column;
}
public int getColumn() {
return column;
}




}



//System.out.print("Please enter first players name:\n");
//String player1=input.next();


First...how do I make the program know that Player one is always the "X" and player two and the computer is always "O"?


next. I have the input from player one. how do I transfer the input of row and column to the board ...I know i can do an if statement in the board such as if playermove == row, column then it replaces board[row][column} i just don't understand how to get it there. I have cut and pasted and typed back and forth and i am not translating what i want right.

Old Pedant
12-11-2009, 09:23 PM
No, you are really missing some very important concepts.

The class HumanPlayer should represent *ONE* player. Period.

Probably, you should have a base class named Player.
And then you have both HumanPlayer and ComputerPlayer classes that derive from (extend) that class.
And you "instantiate" as many of each kind of player as you need.

You could have two objects of class HumanPlayer, two of class ComputerPlayer, or one of each.

And then you have methods on Player that are *implemented* differently by the HumanPlayer and ComputerPlayer.

For example, only:

public interface Player
{
public String getName();
public CellNumber getMove();
}
public class ComputerPlayer implements Player
{
public String getName() { return "Computer"; }
...
}
public class HumanPlayer implements Player
{
private String _name;
public void setName(String name) { _name = name; }
public String getName() { return _name; }
...
}

And so on. Pardon me if I make a syntax error. Been writing all C++ code lately and my head can sometimes get in the wrong space.

mdnealy
12-11-2009, 09:45 PM
that makes sense but we didn't get to interfaces...in the assignment tthe human player prompts and returns the row and column and stores the name of the players.

the computer class generates and returns the value for row and column
and the board sets the return x and o from those two classes..

Old Pedant
12-11-2009, 09:56 PM
Fine. So have a single Player class with a flag that says whether the player is human or not.

public class Player
{
private boolean isHuman = false;
private String _name = "Computer";

public Player( String name )
{
_name = name;
isHuman = ! name.equals("Computer");
}

public cellNumber getMove( )
{
cellNumber move = new cellNumber(-1,-1);
if ( isHuman )
{
... prompt for and get coordinates ...
} else {
... use artificial intelligence to make the move ...
}
return move;
}
... other methods? ...
}

mdnealy
12-11-2009, 10:06 PM
how does it store it on the board...cellNumber knows to go to the board and put it in?

Old Pedant
12-11-2009, 10:22 PM
Actually, if you only have the one Player class, then the getMove() method should indeed just return void after actually putting the move into the right cell.

So...
public class Player
{
private boolean isHuman = false;
private String _name = null;
private TicTacToeEnum xORo = null;

public Player( String name, TicTacToeEnum whichPlayer )
{
_name = name;
isHuman = ! name.equals("Computer");
xORo = whichPlayer;
}

public void getMove( )
{
int rowMove;
int colMove;
while ( true )
{
if ( isHuman )
{
... prompt for and get coordinates into rowMove and colMove ...
} else {
... use artificial intelligence to make the move ...
}
if ( rowMove < 0 || rowMove > 2 || colMove < 0 || colMove > 2
board[rowMove][colMove] != TicTacToeEnum.Empty
)
{
... invalid move message ...
} else {
board[rowMove][colMove] = xOro;
return; // move succeeded
}
} // end of the infinite while loop
}
... other methods? ...

mdnealy
12-11-2009, 10:44 PM
Hope your around tomorrow...have to work..thanks for that and it makes more sense...will play with that and post tomorrow should i run into anything else. thank you so much for your help. though I have changed some stuff around to fit what he has taught us, your help has made all those pieces come together where it makes more sense. until tomorrow....

mdnealy
12-13-2009, 03:44 PM
public class TicTacToeBoard
{

//private boolean move=false;

private TicTacToeEnum[][] board;

public TicTacToeBoard(){
board=new TicTacToeEnum[3][3];
{

board[0][0]= TicTacToeEnum.Empty;
board[0][1]= TicTacToeEnum.Empty;
board[0][2]= TicTacToeEnum.Empty;
board[1][0]= TicTacToeEnum.Empty;
board[1][1]= TicTacToeEnum.Empty;
board[1][2]= TicTacToeEnum.Empty;
board[2][0]= TicTacToeEnum.Empty;
board[2][1]= TicTacToeEnum.Empty;
board[2][2]= TicTacToeEnum.Empty;}}




String rowToText(int row)
{ //int row = hp.getRow();
return getValue (board[row][0]) + " | "
+ getValue(board[ row][1]) + " | "
+ getValue(board[row][2]);
}
void showBoard( )
{
System.out.println("| " + rowToText(0)+ " | ");
System.out.println("----------");
System.out.println("| " +rowToText(1)+ " | ");
System.out.println("----------");
System.out.println("| " +rowToText(2)+ " | ");
}



public String getValue(TicTacToeEnum ticTacToeEnum)
{
String letterDescription = "";
if (ticTacToeEnum ==TicTacToeEnum.X){
letterDescription = "X";
}
else
if (ticTacToeEnum==TicTacToeEnum.O){
letterDescription = "O";
}
return letterDescription;
}

HumanPlayer hp=new HumanPlayer();

public void getPlayer1Move(){
if (hp.getRow()<0 || hp.getRow() >2 || hp.getCol() <0 || hp.getCol() >2 & board [hp.getRow()][hp.getCol()] != TicTacToeEnum.Empty){
System.out.println("invalid move");
}else{
board [hp.getRow()][hp.getCol()] = TicTacToeEnum.X;}
}

public void getPlayer2Move(){
if (hp.getRow()<0 || hp.getRow() >2 || hp.getCol() <0 || hp.getCol() >2 & board [hp.getRow()][hp.getCol()] != TicTacToeEnum.Empty){
}else{
board [hp.getRow()][hp.getCol()] = TicTacToeEnum.O;
}

}

}

Okay, in the above code, I am trying to say in player 1, if hp.getRow and hp.getCol are less than or greater than 2 (which are my array parameters) then it remains empty and a invalid message is generated....else...they equal x

it prints in the board always in the 0,0 position.


I have this working so far but the input from the user(in another class) is not printing in what they put. I usually use 1,1..and it still prints in 0,0

Old Pedant
12-13-2009, 06:06 PM
You still aren't thinking abstractly enough.

Look, game play should be something along these lines:

public Player getOnePlayer(int which)
{
... prompt with "is player " + which + " human?"
if ( ..no.. )
{
return new Player( "Computer" );
} else {
... get name of human player ...
return new Player( name );
}
}

public int findWinner( )
{
... scan the board to see if there is a winner ...
... if not, return -1 ...
... if a tie, return 0 ...
... if a winner, return player number 1 of the winner ...
}

public void playOneGame( )
{
Player player1 = getOnePlayer(1);
Player player2 = getOnePlayer(2);
int winner;

while ( ( winner = findWinner() ) < 0 )
{
player1.getMove( );
player2.getMove( );
}
if ( winner == 0 )
{
... message: tie game ...
} else {
... message: the winner was ...
}
}

I already see some improvements to be made. For example, probably better to do

Player players[2];

and then use those array elements, so that the "winner" number can refer to the winning array element.

But never mind, those are refinements. Get the thing working first.

Oh...and you didn't use my concept of how to make a move at all, did you?? *CLEARLY* getMove( ) should be a method on Player that does *ALL* the checking for move validity. The "mainline" code should not be making any "is this a legal move" checks, at all.

[You could argue that there should be a separate Move class that checks for legal moves, and I'd certainly want to do that for something like Chess, but I think doing that as a method on Player is adequate for this game.]

mdnealy
12-13-2009, 06:24 PM
the problem is that we have specifics from the instructor.

for the player class which holds the one player human and the two players only gets the names and the prompt for the row and column.
the computer class hold the computer prompt for move

the board class holds the moves and validates them. so i took what you wrote and broke it across.

when i move the information of row and column from the player to the board class, for some reason it will notput the x in the right cell. it always gets put in the 0,0 cell no matter what the user inputs.

I like your way and it makes sense to me (can't believe i am starting to understand this stuff) but I have to break it down to what he wants..here is his breakdown where things go.


Required Classes
TicTacToeTest.java
• Getting the game started
• Creating the players
• Checking for game win/draw after a move.
TicTacToeEnum.java
• Enumeration
• X, O, or Empty
HumanPlayer.java
• Prompting and returning Row
• Prompting and returning Column
• Stores the name.
ComputerPlayer.java
• Generates and return value for Row
• Generates and return value for Column
• Stores the computer’s name.
TicTacToeBoard
• Contains the array
• Stores all the X,O, or empties
• Check if the move is valid?
• Set an x or o.
• Is the game won?
• Print the board

Old Pedant
12-13-2009, 07:33 PM
Okay, so the ONLY difference between what he has and what I propose are the following:

(1) He has a crappy design of having HumanPlayer and ComputerPlayer classes, but because they don't derive from a common base class, you can't abstract them in the TicTacToeTest class.

Unless...

You said that you haven't done interfaces, yet, but *have* you done base classes and sub classes???? If so, that would be the way to go.

As it is, if there's no common base class (or interface, same thing really) then you can't easily have a game with two human players or two computer players. If that is not a requirement--if you always have one human and one computer player--then his deficiency isn't quite so bad (though it's still there and still a lmiitation).

(2) He moves the logic for checking for a legal move to the Board class. Okay. But that means that your method on the players for getting a move has to return an array of two values: row and column. (It could also return a simple object with row and column values, which would be better but not necessary.) You do *NOT* want to ask for row and column with separate method calls, in my very strong opinion, because it complicates the situation tremendously if (for example) the human player chooses an invalid row or column. Oh, it can be coded that way. It's just ugly as pig snot.

********

But that's about it. Really. You *clearly* should NEVER do stuff like you were starting to do:

if (hp.getRow()<0 || hp.getRow() >2 || hp.getCol() <0 || hp.getCol() >2 & board [hp.getRow()][hp.getCol()] != TicTacToeEnum.Empty){
System.out.println("invalid move");
}else{

Ugh. So each time you called hp.getRow() you would go out and ask the human to input a row number??? Come on!

No!

*********

So...first question? Have you studied base and derived classes yet??? Because, if so, I think *clearly* you should have:

public class Player
{
String _name;
String getName() { return _name; }
String setName(String name) { _name = name; }
int[] getMove( ) { return new int[2]; }
}
public class HumanPlayer extends Player
{
int[] getMove( )
{
int move[2];
move[0] = ... prompt for row number ...
move[1] = ... prompt for column number ...
return move;
}
}
public class ComputerPlayer extends Player
{
int[] getMove( )
{
int move[2];
move[0] = ... use AI to choose row ...
move[1] = ... ditto for column ...
return move;
}
}

Pardon me if I make some silly syntax errors. Been doing all C++ lately and my Java gets fuzzier as the weeks go by.

Old Pedant
12-13-2009, 07:34 PM
forgot to put private/public on members of the classes, but you get the idea.

Old Pedant
12-13-2009, 07:41 PM
What I'm really curious about: Why haven't you created the classes the way he describes them???

In your code in post #23 you are showing your TicTacToeBoard class. And it holds the board. And it initialized the baord.

But then inside *THAT* class you create a new HumanPlayer and you have methods for getPlayer1Move and getPlayer2Move. Does that match at all the model he gave you?? HINT: No.

I quote you:
Required Classes
TicTacToeTest.java
• Getting the game started
• Creating the players
• Checking for game win/draw after a move.


So why not start by creating the 4 classes he requires with dummy methods/members to represent the qualities/actions he requires. Then start filling in the details. Top down. Not bottom up.

mdnealy
12-13-2009, 11:35 PM
i created to the new human player to be able to pull the method from the humanplayer class. okay so, if i make the row and column an array for getting the information how to I move that over to the board to fill the spots on the board?

we got to arrays enumeration, and time. that is it. I presumed creating the players in the test class was to choose which game a one player or two player game.
store the names in human class of first player or second player then computer class the computer name.

so, a very simple code that I guess could be done in a couple of classes is spread out. you show me the human and computer together but I have to separate them. then move whatever each of those classes do over to the board. Remember, I walked in to this class 12 weeks ago, going 2.5 hours a week with NO java knowledge. I have BASICS of some vb and c# but they did not get as far as this.

so, with that, if I make one method move which contains the array for row and column which to me looks like what i did with the board how do I incorporate the row/column array with the board...

maybe I am just a little slow and not seeing the whole picture..I thought i was doing good, got everything to work until I hit putting in the cells...

Old Pedant
12-14-2009, 06:01 AM
You really are close.

And if you don't see how to use the array, then okay, go back to getting row and column separately. It's not ideal, but it will work in this simple system.

I mildly disagree with the "division of labor" given by your instructor, but not so much to call it "wrong".

Just go, again, and examine the classes he wants and the methods/members he wants and implement all of them, first. Even if some of the implementations are temporarily dummy ones.

It's really hard for me to know exactly how close/far you are when I only see fragments of the total code. But you've got a lot of the principles right, so I think you just need some "tweaks".

*******

EDIT: To explain: The reason it's clumsy to get row and column separately from the computer player is that your "artificial intelligence" code for having the computer make a move *MUST* choose both row and column at the same time. (If the computer picked, say, row 1 first and then you call and ask it for a column, it might be completely hosed: there might be no cells still open in row 1.)

So clearly when you call for the row alone, the algorithm has to actually go find a single cell, store both row and column of that cell internal to the ComputerPlayer class, and then return them one at a time.

Okay, it works. But if you ever called for getColumn() *without* calling getRow() first, you'd get a wrong answer (either no answer at all or the same column as for the prior computer move).

Make sense?

It's unfortunate that he wants the two players as separate classes and yet you can't use a common base class for them (yet). I would say that it means that writing the gameplay is too difficult unless you assume that the computer player always goes first (or always second...but in any case always the same position).

Because your game play needs to look like this:

TicTacToeTest.java
• Getting the game started
• Creating the players
• Checking for game win/draw after a move.

So:

public class TicTacToeTest
{
// Getting the game started
TicTacToeBoard board = new TicTacToeBoard();

// Creating the players
ComputerPlayer p1 = new ComputerPlayer( );
HumanPlayer p2 = new HumanPlayer( );

while ( true )
{
int[] p1Move = p1.getMove( );
board.setMoveIfValid( p1Move, TicTacToeEnum.X );
if ( board.gameOver( ) ) break; // out of loop
int[] p2Move = p2.getMove( );
board.setMoveIfValid( p2Move, TicTacToeEnum.O );
if ( board.gameOver( ) ) break; // out of loop
}
if ( board.gameIsTie( ) )
{
... write out Tie message ...
} else {
TicTacToeEnum winner = board.getWinner( );
... write out winner ...
}
}

But, as I said, if you are uncomfortable with the idea of getting the array for the move, you can finesse it:

while ( true )
{
int p1Row = p1.getRowMove( );
int p1Col = p1.getColMove( );
board.setMoveIfValid( p1Row, p1Col, TicTacToeEnum.X );
if ( board.gameOver( ) ) break; // out of loop
int p2Row = p2.getRowMove( );
int p2Col = p2.getColMove( );
board.setMoveIfValid( p2Row, p2Col, TicTacToeEnum.O );
if ( board.gameOver( ) ) break; // out of loop
}

I think it's clumsier, especially for the computer player, to get the row and column with separate method calls. But clearly it can be done.

Old Pedant
12-14-2009, 06:15 AM
By the by, you are doing a *LOT* better than many people we've seen who are 12 weeks into a course like this. I strongly suspect you could hack this thing to make it work right now. Just that you might not be following the outline the instructor gave you.

I personally feel like this project is being given to you a little too early. It really is ripe for the use of a base class ("Player", as the base of both ComputerPlayer and HumanPlayer), and without the ability to use that feature the gameplay is harder to code and a bit uglier. My opinion.

mdnealy
12-14-2009, 04:02 PM
The biggest thing for this instructor is to get the program to work in what he has taught us. He is okay with variance here and there. Okay..here is what I have so far and I am still stuck with getting the move placed in the board after being checked for valid. I put valid on the board and called the method to the test. the same will be for if they win..but i need to get the x's and o's in the board. Here is the code for the test, human player(s), and the board, of course I have an enum but that is a given...

import java.util.Scanner;


public class TicTacToeTest {


public static void main(String[] args) {
Scanner input= new Scanner(System.in);
HumanPlayer hp = new HumanPlayer();
TicTacToeBoard bd = new TicTacToeBoard();

System.out.println("Main Menu\n WELCOME TO TIC-TAC-TOE!");
System.out.println();
System.out.println("PLAYER 1 IS ALWAYS X ");
System.out.println();
System.out.println("1. One player game.\n2. Two player game.");

System.out.print("Please Select: ");
int game= input.nextInt();
//System.out.printf("selection=%d", game);

if ( game==1){

System.out.println("One Player Game\nWho will go first?\n1. Me.\n2. The Computer.");
System.out.print("Please Select: ");
int choice= input.nextInt();
System.out.printf("selection=%d", choice);}


if (game ==2){
System.out.println("Two Player Game");
//System.out.print("PLease enter first player name:");
//String player1;
hp.getFirstPlayer();
hp.getSecondPlayer();
bd.showBoard();
System.out.print(hp.getPlayer1(TicTacToeEnum.X) + ", Please enter your moves\n");
hp.getRowMove();
hp.getColMove();
int row = hp.getRow();
int col = hp.getCol();
bd.isMoveValid(row, col);

boolean isValid = board.isMoveValid(row, col);
if (isValid) {
board.move(row,col, x_or_o);


}
}

}






the board:


public class TicTacToeBoard
{



private TicTacToeEnum[][] board;

public TicTacToeBoard(){
board=new TicTacToeEnum[3][3];
{

board[0][0]= TicTacToeEnum.Empty;
board[0][1]= TicTacToeEnum.Empty;
board[0][2]= TicTacToeEnum.Empty;
board[1][0]= TicTacToeEnum.Empty;
board[1][1]= TicTacToeEnum.Empty;
board[1][2]= TicTacToeEnum.Empty;
board[2][0]= TicTacToeEnum.Empty;
board[2][1]= TicTacToeEnum.Empty;
board[2][2]= TicTacToeEnum.Empty;}}




String rowToText(int row)
{ //int row = hp.getRow();
return getValue (board[row][0]) + " | "
+ getValue(board[ row][1]) + " | "
+ getValue(board[row][2]);
}
void showBoard( )
{
System.out.println("| " + rowToText(0)+ " | ");
System.out.println("----------");
System.out.println("| " +rowToText(1)+ " | ");
System.out.println("----------");
System.out.println("| " +rowToText(2)+ " | ");
}



public String getValue( TicTacToeEnum ticTacToeEnum)
{
String letterDescription = "";
if (ticTacToeEnum ==TicTacToeEnum.X){
letterDescription = "X";
}
else
if (ticTacToeEnum==TicTacToeEnum.O){
letterDescription = "O";
}
return letterDescription;
}

HumanPlayer hp=new HumanPlayer();

int row = hp.getRowMove();
int col = hp.getColMove();




//private boolean move= getMove(Player1,Player2);
private boolean isValid= isMoveValid(row,col);

public boolean isMoveValid(int row, int col){
if ( row <0 || row >2 || col <0||col>2){
System.out.println("invalid move");
}else {
board [row][col]= hp.getTicTacToeEnum() ; }

return isValid;
}




// public boolean getMove(String Player1, String Player2){
// if (isValid == Player1){
// {
// board[row][col]= TicTacToeEnum.X;
// }
//




public void setValid(boolean isValid) {
this.isValid = isValid;
}




public boolean isValid() {
return isValid;
}

// public void getPlayer2Move(){
public void check()
{
int i;

for(i=0; i<3; i++) /* check rows */
if((board[i][0]==board[i][1]) &&
( board[i][0]==board[i][2])!= isValid()||
(board[0][i]==board[1][i]) &&
( board[0][i]==board[2][i])!= isValid()||
(board[0][0]==board[1][1]) &&
(board[1][1]==board[2][2])!= isValid()||
( board[0][2]==board[1][1]) &&
(board[1][1]==board[2][0])!= isValid()){
System.out.println("game won");}
else{
System.out.println("game lost");}
}


}




the humanplayer:
import java.util.Scanner;


public class HumanPlayer {



private String firstPlayer ;
private String secondPlayer;
private int rowMove;
private int colMove;
// TicTacToeBoard bd = new TicTacToeBoard();


// public HumanPlayer(String player1, String player2, Integer row, Integer column){
// setFirstPlayer(player1);
// setSecondPlayer(player2);
// setRowMove(row);
// setColMove(column);}



Scanner input = new Scanner(System.in);
private TicTacToeEnum x_or_o;
public void setFirstPlayer(String firstPlayer) {
this.firstPlayer = firstPlayer;
}
public String getFirstPlayer() {
System.out.print("please enter Player 1 name:");
firstPlayer= input.next();
return firstPlayer;
}

public void setSecondPlayer(String secondPlayer) {
this.secondPlayer = secondPlayer;
}
public String getSecondPlayer() {
System.out.print("Please enter Player 2 name:");
secondPlayer=input.next();
return secondPlayer;
}
public void setRowMove(int rowMove) {
this.rowMove = rowMove;
}

public int getRowMove(){

System.out.print( "Enter row:");
rowMove= input.nextInt();
return rowMove;

}
public void setColMove(int colMove) {
this.colMove = colMove;
}
public int getColMove(){
System.out.print( "Enter column:");
colMove= input.nextInt();
return colMove;}


public String getPlayer1(TicTacToeEnum X){
return firstPlayer;
}
public String getPlayer2(TicTacToeEnum O){
return secondPlayer;}

public int getRow() {
return rowMove;
}
public int getCol(){
return colMove;
}
public void setTicTacToeEnum(TicTacToeEnum x_or_o) {
this. x_or_o = x_or_o;
}

public TicTacToeEnum getTicTacToeEnum() {
return x_or_o;
}

}


now, I have no read lines but i am getting a null expression in my boolean..

by the way, the majority has been help from you and I have been emailing my instructor getting input also..so some of the changes are not "ignoring" you, just an adjustment from what he may want to see...this is killing me only two days left to get it and I haven't even done the computer class with random or what ever to make the computer pick..please tell me that one will be easier :(

Old Pedant
12-14-2009, 07:11 PM
Look, I know it may not 100% fulfill the requirements, but you need to drop the idea of 1 or 2 player game.

I say again: Unless you can have HumanPlayer and ComputerPlayer both be subclasses of Player, it is way too difficult to do the 1 or 2 player game.

And in any case, your way of doing two human players simply isn't going to work right.

SIMPLIFY!

One human player, one computer player.

Trust me on this.

You can tell the instructor that you understand that if both were subclasses you could make the game more general.

Go ahead and start working on the computer player. Yes, you could start with simply picking a spot on the board at random, checking to see if it is empty. If not, you pick again. Keep picking until you find an empty cell. It's not great strategy, but it's more important to get it working.

NOTE: One thing this means is that when you call the ComputerPlayer's "getMove( )" method, you will need to PASS IN the board as an argument! Otherwise, that method won't be able to "see" it. (The HumanPlayer actually needs the same thing, but the difference is that the board is "passed in" to the human player by displaying it on the screen. Kind of end-around of the computer process.)

mdnealy
12-15-2009, 06:23 AM
Okay, I know I need to get the information from the computer and place it in the board. so, on my return statement is where I have the problem. how do I get the move I want into the board. I think that is the biggest thing I cannot see. is If I need to get a value from computer class like two integers, how do I write the syntax to get the integers from computer into the board? I see the row to text but where do I put the computers stuff???

Please see the bottom for my questions...

public class ComputerPlayer {

private String computer;
private int row;
private int col;
private TicTacToeEnum x_or_o;





TicTacToeBoard bd = new TicTacToeBoard();
HumanPlayer hp = new HumanPlayer();
public void setComputer(String computer) {
this.computer = computer;
}
public String getcomputer(TicTacToeEnum O) {

return computer;
}


public void setTicTacToeEnum(TicTacToeEnum x_or_o) {
this. x_or_o = x_or_o;
}

public TicTacToeEnum getTicTacToeEnum() {
return x_or_o;}



public int getMove(int row,int col){

if((bd.board[0][0] == TicTacToeEnum.X) && (bd.board[0][1] == TicTacToeEnum.X) && (bd.board[0][2] == TicTacToeEnum.Empty));
return bd.board[0][2]== getMove(0,2) ;

if ((bd.board[1][0] == TicTacToeEnum.X) && (bd.board[1][1] == TicTacToeEnum.X) && (bd.board[1][2] == TicTacToeEnum.Empty));
return bd.board[1][2];

if{((bd.board[2][0] == TicTacToeEnum.X) && (bd.board[2][1] == TicTacToeEnum.X) && (bd.board[2][2] == TicTacToeEnum.Empty));
return bd.board[2][2];

else if((bd.board[0][1] == TicTacToeEnum.X) && (bd.board[0][2] == TicTacToeEnum.X) && (bd.board[0][0] == TicTacToeEnum.Empty));
return bd.board[0][0];
else if((bd.board[1][1] == TicTacToeEnum.X) && (bd.board[1][5] == TicTacToeEnum.X) && (bd.board[1][0] == TicTacToeEnum.Empty));
return bd.board[1][0];
else if((bd.board[2][1] == TicTacToeEnum.X) && (bd.board[2][8] == TicTacToeEnum.X) && (bd.board[2][0] == TicTacToeEnum.Empty));
return bd.board [2][0];

else if((bd.board[0][0] == TicTacToeEnum.X) && (bd.board[0][2] == TicTacToeEnum.X) && (bd.board[0][1] == TicTacToeEnum.Empty));
return bd.board[0][1];
else if((bd.board[1][0] == TicTacToeEnum.X) && (bd.board[1][5] == TicTacToeEnum.X) && (bd.board[1][4] == TicTacToeEnum.Empty));
return bd.board[1][1];
else if((bd.board[2][0] == TicTacToeEnum.X) && (bd.board[2][8] == TicTacToeEnum.X) && (bd.board[2][7] == TicTacToeEnum.Empty));
return bd.board[2][1];

else if((bd.board[0][0] == TicTacToeEnum.X) && (bd.board[1][0] == TicTacToeEnum.X) && (bd.board[2][0] == TicTacToeEnum.Empty));
return bd.board[2][0];
else if((bd.board[0][1] == TicTacToeEnum.X) && (bd.board[1][4] == TicTacToeEnum.X) && (bd.board[2][1] == TicTacToeEnum.Empty));
return bd.board[2][1];
else if((bd.board[0][2] == TicTacToeEnum.X) && (bd.board[1][5] == TicTacToeEnum.X) && (bd.board[2][2] == TicTacToeEnum.Empty));
return bd.board[2][2];

else if((bd.board[1][0] == TicTacToeEnum.X) && (bd.board[2][0] == TicTacToeEnum.X) && (bd.board[0][0] == TicTacToeEnum.Empty));
return bd.board[0][0];
else if((bd.board[1][1] == TicTacToeEnum.X) && (bd.board[2][1] == TicTacToeEnum.X) && (bd.board[0][1] == TicTacToeEnum.Empty));
return bd.board[0][1];
else if((bd.board[1][2] == TicTacToeEnum.X) && (bd.board[2][2] == TicTacToeEnum.X) && (bd.board[0][2] == TicTacToeEnum.Empty));
return bd.board[0][2];

else if((bd.board[0][0] == TicTacToeEnum.X) && (bd.board[2][0] == TicTacToeEnum.X) && (bd.board[1][0] == TicTacToeEnum.Empty));
return bd.board[1][0];
else if((bd.board[0][1] == TicTacToeEnum.X) && (bd.board[2][1] == TicTacToeEnum.X) && (bd.board[1][1] == TicTacToeEnum.Empty));
return bd.board[1][1];
else if((bd.board[0][2] == TicTacToeEnum.X) && (bd.board[2][2] == TicTacToeEnum.X) && (bd.board[1][2] == TicTacToeEnum.Empty));
return bd.board[1][2];

else if((bd.board[0][0] == TicTacToeEnum.X) && (bd.board[1][1] == TicTacToeEnum.X) && (bd.board[2][2] == TicTacToeEnum.Empty));
return bd.board[2][2];
else if((bd.board[1][1] == TicTacToeEnum.X) && (bd.board[2][2] == TicTacToeEnum.X) && (bd.board[0][0] == TicTacToeEnum.Empty));
return bd.board[0][0];
else if((bd.board[0][0] == TicTacToeEnum.X) && (bd.board[2][8] == TicTacToeEnum.X) && (bd.board[1][4] == TicTacToeEnum.Empty));
return bd.board[1][1];

else if((bd.board[0][2] == TicTacToeEnum.X) && (bd.board[1][1] == TicTacToeEnum.X) && (bd.board[2][0] == TicTacToeEnum.Empty));
return bd.board[0][2];
else if((bd.board[1][1] == TicTacToeEnum.X) && (bd.board[2][0] == TicTacToeEnum.X) && (bd.board[0][2] == TicTacToeEnum.Empty));
return bd.board[0][2];
else if((bd.board[0][2] == TicTacToeEnum.X) && (bd.board[2][0] == TicTacToeEnum.X) && (bd.board[1][1] == TicTacToeEnum.Empty));
return bd.board[1][1];

else if((bd.board[0][0] == TicTacToeEnum.X) && (bd.board[1][1] == TicTacToeEnum.O) && (bd.board[2][2] == TicTacToeEnum.X));
return bd.board[1][2];

else if((bd.board[0][2] == TicTacToeEnum.X) && (bd.board[1][1] == TicTacToeEnum.O) && (bd.board[2][0] == TicTacToeEnum.X));
return bd.board[1][0];

else if(bd.board[1][1] == TicTacToeEnum.Empty);
return bd.board[1][1];

else if(bd.board[0][0] == TicTacToeEnum.Empty);
return bd.board[0][0];
return location;
}


the board class:
public class TicTacToeBoard
{

//private boolean isValid()=false;

public TicTacToeEnum[][] board;

public TicTacToeBoard(){
board =new TicTacToeEnum[3][3];
{

board[0][0]= TicTacToeEnum.Empty;
board[0][1]= TicTacToeEnum.Empty;
board[0][2]= TicTacToeEnum.Empty;
board[1][0]= TicTacToeEnum.Empty;
board[1][1]= TicTacToeEnum.Empty;
board[1][2]= TicTacToeEnum.Empty;
board[2][0]= TicTacToeEnum.Empty;
board[2][1]= TicTacToeEnum.Empty;
board[2][2]= TicTacToeEnum.Empty;}}




String rowToText(int row)
{ //int row = hp.getRow();
return getValue (board[row][0]) + " | "
+ getValue(board[ row][1]) + " | "
+ getValue(board[row][2]);
}
void showBoard( )
{
System.out.println("| " + rowToText(0)+ " | ");
System.out.println("----------");
System.out.println("| " +rowToText(1)+ " | ");
System.out.println("----------");
System.out.println("| " +rowToText(2)+ " | ");
}



public String getValue( TicTacToeEnum ticTacToeEnum)
{
String letterDescription = "";
if (ticTacToeEnum ==TicTacToeEnum.X){
letterDescription = "X";
}
else
if (ticTacToeEnum==TicTacToeEnum.O){
letterDescription = "O";
}
return letterDescription;
}

HumanPlayer hp=new HumanPlayer();

public boolean isMoveValid(int row, int col) {
// TODO Auto-generated method stub
return false;
}




public void move(int row, int col) {
// TODO Auto-generated method stub

}









// int row = hp.getRow();
// int col = hp.getCol();
//
// //private boolean move= getMove(Player1,Player2);
// private boolean isValid= isMoveValid(row,col);
////
// public boolean isMoveValid(int row, int col){
// if ( row <0 || row >2 || col <0||col>2){
// System.out.println("invalid move");
// }else {
// board [row][col]= hp.getTicTacToeEnum() ; }
////
// return isValid;}}
// }




// public boolean getMove(String Player1, String Player2){
// if (isValid == Player1){
// {
// board[row][col]= TicTacToeEnum.X;
// }
//




// public void setValid(boolean isValid) {
// this.isValid = isValid;
// }
//
//
//
//
// public boolean isValid() {
// return isValid;
// }


// public void getPlayer2Move(){
// public void check()
// {
// int i;
//
// for(i=0; i<3; i++) /* check rows */
// if((board[i][0]==board[i][1]) &&
// ( board[i][0]==board[i][2])!= isValid()||
// (board[0][i]==board[1][i]) &&
// ( board[0][i]==board[2][i])!= isValid()||
// (board[0][0]==board[1][1]) &&
// (board[1][1]==board[2][2])!= isValid()||
// ( board[0][2]==board[1][1]) &&
// (board[1][1]==board[2][0])!= isValid()){
// System.out.println("game won");}
// else{
// System.out.println("game lost");}
// }
//
//
// }


1. for computer class...how do I write getMove so that I can take the row and column and transfer it to the board class

2. for the board class...I have the two integers from the computer class, where do I put them in the board class code so that it will display in the board..I know rowto text I am just not sure how to get the information there..

3. for some reason I cannot figure out this boolean stuff...I understand it returns a true or false but I don't see how it works in the code and where to put the stuff or write the correct syntax


deadline approaching..tomorrow at 7 pm my time (EST) hopefully i can get this *&%^ to compile...

thanks again for all your help!!

Old Pedant
12-15-2009, 07:30 PM
You've *still* got all that stuff in the WRONG CLASS.

Go look again at what the instructor said to put in the TicTacToeBoard class:

TicTacToeBoard
• Contains the array
• Stores all the X,O, or empties
• Check if the move is valid?
• Set an x or o.
• Is the game won?
• Print the board

Oh, w.t.h. Here's how I see that class:

public class TicTacToeBoard
{
// Requirements:
// Contains the array
// Stores all the X,O, or empties
// Check if the move is valid?
// Set an x or o.
// Is the game won?
// Print the board

// Fulfills: Contains the array
private TicTacToeEnum[][] board;

// Fulfills: Stores X,O,Empties
public TicTacToeBoard()
{
board = new TicTacToeEnum[3][3];
board[0][0]= TicTacToeEnum.Empty;
board[0][1]= TicTacToeEnum.Empty;
board[0][2]= TicTacToeEnum.Empty;
board[1][0]= TicTacToeEnum.Empty;
board[1][1]= TicTacToeEnum.Empty;
board[1][2]= TicTacToeEnum.Empty;
board[2][0]= TicTacToeEnum.Empty;
board[2][1]= TicTacToeEnum.Empty;
board[2][2]= TicTacToeEnum.Empty;
}


// helper methods for showing the board
private String enumToString(TicTacToeEnum playType)
{
switch ( playType )
{
case TicTacToeEnum.X: return "X";
case TicTacToeEnum.O: return "O";
case else: return " ";
}
}
private String rowToText(int row)
{
return enumToString(board[row][0]) + " | "
+ enumToString(board[row][1]) + " | "
+ enumToString(board[row][2]);
}
// Fufills: Print the board
public void showBoard( )
{
System.out.println("| " + rowToText(0)+ " | ");
System.out.println("----------");
System.out.println("| " +rowToText(1)+ " | ");
System.out.println("----------");
System.out.println("| " +rowToText(2)+ " | ");
}

// Fullfills: Check if the move is valid?
public boolean isMoveValid(int row, int col)
{
if ( row < 0 || row > 2 || col < 0 || col > 2 ) return false;
if ( board[row][col] != TicTacToeEnum.Empty ) return false;
return trud;
}

// Fullfills: Set an x or o.
public void move(int row, int col, TicTacToeEnum playType )
{
if ( isMoveValid(row,col) ) board[row][col] = playType;
}

// Fullfills: Is the game won?
public boolean isGameTie( )
{
// if game won by either player, it is not a tie
if ( isGameWonBy( TicTacToeEnum.X ) ) return false;
if ( isGameWonBy( TicTacToeEnum.O ) ) return false;
// if all cells are filled, it is a tie:
for ( int row = 0; row < 3; ++row )
{
for ( int col = 0; col < 3; ++col )
{
if ( board[row][col] != TicTacToeEnum.Empty ) return false;
}
}
return true;
}
// Fullfills: Is the game won?
public boolean isGameWonBy( TicTacToeEnum playType )
{
... and this is the tricky one that I will let you code ...
}

}


AND THAT IS THAT! I see NO REASON for ANY other code in that class.

Period.

CLEARLY that class should *NOT* be aware of what kinds of playes (Human vs. Computer) there are. Clearly it should not be asking either the computer or human for a move.

Old Pedant
12-15-2009, 07:51 PM
And I really don't understand why you think the the ComputerPlayer class would *contain* a TicTacToeBoard or a HumanPlayer.

W.T.H., again. A sample ComputerPlayer:


public class ComputerPlayer
{
private TicTacToeEnum x_or_o = TicTacToeEnum.X; // defaults to play X

public String name() { return "Computer"; }
public TicToeEnum getPlayType( ) { return x_or_o; }
public void setPlayType( TicTacToeEnum e ) { x_or_o = e; }

public void makeMove( TicTacToeBoard theBoard )
{
while ( true )
{
int row = Math.floor( Math.random() * 3 );
int col = Math.floor( Math.random() * 3 );
if ( theBoard.isMoveValid( row, col ) )
{
theBoard.move( row, col, this.getPlayType() );
return;
}
}
}
}

Not a very intelligent move picker, but at least it should work.

Note that if you call makeMove when the board is already full, it will loop infinitely. So make sure you don't do that.

mdnealy
12-16-2009, 05:25 AM
I know you are all getting frustrated but here what I have thanks to "Old"..

1. I have an error on the at the enumToString where the first "" says that it is never read. I changed this because it would not accept the return part of the case. So I am not sure why that warning is there but both ways gives me errors.

2. in the test, i have gotten to the make move from the player side. I have no errors in the humanplayer class, so it must be the way that I am calling the method.

3. Please disregard player 2 in the human player class. it is just sitting there until I can get the human vs computer running then i will work on the two player game.

4. in computer player i had to change all code across the board to double because of the random.

5. Here is the code for the board, test, computer and human player...

Board:
public class TicTacToeBoard
{
// Requirements:
// Contains the array
// Stores all the X,O, or empties
// Check if the move is valid?
// Set an x or o.
// Is the game won?
// Print the board

// Fulfills: Contains the array
private TicTacToeEnum[][] board;

// Fulfills: Stores X,O,Empties
public TicTacToeBoard()
{
board = new TicTacToeEnum[3][3];
board[0][0]= TicTacToeEnum.Empty;
board[0][1]= TicTacToeEnum.Empty;
board[0][2]= TicTacToeEnum.Empty;
board[1][0]= TicTacToeEnum.Empty;
board[1][1]= TicTacToeEnum.Empty;
board[1][2]= TicTacToeEnum.Empty;
board[2][0]= TicTacToeEnum.Empty;
board[2][1]= TicTacToeEnum.Empty;
board[2][2]= TicTacToeEnum.Empty;
}


// helper methods for showing the board
private String enumToString(TicTacToeEnum playType)
{

String enumToString ="";
if (playType ==TicTacToeEnum.X){
enumToString = "X";
}
else
if (playType==TicTacToeEnum.O){
enumToString = "O";
}
return enumToString="";
}



private String rowToText(double row)
{
return enumToString(board[(int)row][0]) + " | "
+ enumToString(board[(int) row][1]) + " | "
+ enumToString(board[(int) row][2]);
}
// Fufills: Print the board
public void showBoard( )
{
System.out.println("| " + rowToText(0)+ " | ");
System.out.println("----------");
System.out.println("| " +rowToText(1)+ " | ");
System.out.println("----------");
System.out.println("| " +rowToText(2)+ " | ");
}


public boolean isMoveValid(double row, double col)
{
if ( row < 0 || row > 2 || (int)col < 0 || (int)col > 2 ) return false;
if ( board[(int) row][ (int)col] != TicTacToeEnum.Empty ) return false;
return true;
}


public void move(double row, double col, TicTacToeEnum playType )
{
if ( isMoveValid((int)row,(int) col )) board[(int) row][(int) col] = playType;
}


public boolean isGameTie( )
{

if ( isGameWonBy( TicTacToeEnum.X ) ) return false;
if ( isGameWonBy( TicTacToeEnum.O ) ) return false;

for ( int row = 0; row < 3; ++row )
{
for ( int col = 0; col < 3; ++col )
{
if ( board[(int)row][(int)col] != TicTacToeEnum.Empty ) return false;
}
}
return true;
}

public boolean isGameWonBy( TicTacToeEnum playType )
{
if ( isGameWonBy( TicTacToeEnum.X ) ) return true;
else
if( isGameWonBy( TicTacToeEnum.X ) ) return false;

if ( isGameWonBy( TicTacToeEnum.O ) ) return false;
else
if( isGameWonBy( TicTacToeEnum.O ) ) return true;



for ( int row = 0; row < 3; ++row )
{
for ( int col = 0; col < 3; ++col )
{ /* check rows */
if((board[0][0]==board[0][1] && board[0][0]==board[0][2])||(board[1][0]==board[1][1] && board[1][0]==board[1][2])||
(board[2][0]==board[2][1] && board[2][0]==board[2][2])){
return true;
}
else
if((board[0][0]==board[1][0] && board[0][0]==board[2][0])||(board[0][1]==board[1][1] && board[0][1]==board[2][1])||
(board[0][2]==board[1][2] && board[0][2]==board[2][2])){
return true;
}
else
if((board[0][0]==board[1][1] && board[1][1]==board[2][2])||(board[0][2]==board[1][1] && board[1][1]==board[2][0])){
return true;
}


}
}
return true;
}


}

Test:
import java.util.Scanner;


public class TicTacToeTest {


public static final void main(String[] args) {
Scanner input= new Scanner(System.in);
HumanPlayer hp = new HumanPlayer();
TicTacToeBoard bd = new TicTacToeBoard();
ComputerPlayer cp = new ComputerPlayer();
System.out.println("Main Menu\n WELCOME TO TIC-TAC-TOE!");
System.out.println();
System.out.println("PLAYER 1 IS ALWAYS X ");
System.out.println();
System.out.println("1. One player game.\n2. Two player game.");

System.out.print("Please Select: ");
int game= input.nextInt();


if ( game==1){

System.out.println("One Player Game\nWho will go first?\n1. Me.\n2. The Computer.");

System.out.print("Please Select: ");
int choice= input.nextInt();


//do{
if (choice ==1){

hp.getFirstPlayer();
bd.showBoard();
hp.makeMove(bd);
int row= hp.getRowMove();
int col=hp.getColMove();
bd.move( row, col, TicTacToeEnum.X);
bd.showBoard();


} }
}
}


humanplayer
import java.util.Scanner;


public class HumanPlayer {

private TicTacToeEnum x_or_o = TicTacToeEnum.O;
private int row;
private int col;
private String firstPlayer;
private String secondPlayer;
//public String secondPlayer;
public TicTacToeEnum getPlayType( ) { return x_or_o; }
public void setPlayType( TicTacToeEnum e ) { x_or_o = e; }
Scanner input = new Scanner(System.in);

public void makeMove( TicTacToeBoard theBoard )
{
while ( true )
{

System.out.print("Please enter row:");
int row = input.nextInt();
System.out.print("Please enter column:");
int col = input.nextInt();

if ( theBoard.isMoveValid(( (int)row), ((int) col ) ))
{
theBoard.move( (int)row,(int) col, this.getPlayType() );
return;}

}


}


public void setFirstPlayer(String firstPlayer) {
this.firstPlayer = firstPlayer;
}
public String getFirstPlayer() {
System.out.print("please enter Player 1 name:");
firstPlayer= input.next();
return firstPlayer;
}

public void setSecondPlayer(String secondPlayer) {
this.secondPlayer = secondPlayer;
}
public String getSecondPlayer() {
System.out.print("please enter Player 2 name:");
secondPlayer= input.next();
return secondPlayer;
}

public int getRowMove(){
return row;
}

public int getColMove(){
return col;
}

}


computer:
public class ComputerPlayer
{
private TicTacToeEnum x_or_o = TicTacToeEnum.X;

public String name() { return "Computer"; }
public TicTacToeEnum getPlayType( ) { return x_or_o; }
public void setPlayType( TicTacToeEnum e ) { x_or_o = e; }

public void makeMove( TicTacToeBoard theBoard )
{
while ( true )
{
double row = Math.floor( Math.random() * 3 );
double col = Math.floor( Math.random() * 3 );

if ( theBoard.isMoveValid( row, col ) )
{
theBoard.move( row, col, this.getPlayType() );
return;
}
}
}
}


thanks again for your help...hopefully this will finish up tomorrow..

Old Pedant
12-16-2009, 05:38 AM
Clearly this code is wrong:
// helper methods for showing the board
private String enumToString(TicTacToeEnum playType)
{

String enumToString ="";
if (playType ==TicTacToeEnum.X){
enumToString = "X";
}
else
if (playType==TicTacToeEnum.O){
enumToString = "O";
}
return enumToString="";
}

(1) You never return anything if the playType is X or O.
(2) You return "" (instead of a space) if the space is empty.

I don't know why the switch didn't work for you, but let's move on. Change that code to this:
// helper methods for showing the board
private String enumToString(TicTacToeEnum playType)
{
if (playType ==TicTacToeEnum.X) return "X";
if (playType==TicTacToeEnum.O) return "O";
return " "; // a space! not a blank string!
}

Old Pedant
12-16-2009, 05:46 AM
And I refuse to go along with your attempts to have 2 human players. I say again that your approach is ALL WRONG.

I will give you a POSSIBLE answer:
public class HumanPlayer
{
private TicTacToeEnum x_or_o = TicTacToeEnum.O;
private String playerName = "Human";
private Scanner input = new Scanner(System.in);

// constructor:
public HumanPlayer( String name, TicTacToeEnum playType )
{
playerName = name;
x_or_o = playType;
}

// get/set methods (probably don't need the set methods):
public String name() { return playerName; }
public void setName( String name ) { playerName = name; }
public TicTacToeEnum getPlayType( ) { return x_or_o; }
public void setPlayType( TicTacToeEnum e ) { x_or_o = e; }

public void makeMove( TicTacToeBoard theBoard )
{
while ( true )
{
System.out.print("Please enter row:");
int row = input.nextInt();
System.out.print("Please enter column:");
int col = input.nextInt();

if ( theBoard.isMoveValid(( (int)row), ((int) col ) ))
{
theBoard.move( (int)row,(int) col, this.getPlayType() );
return;
}
} // end of infinite loop
}

} // end of class


If you really decide you want 2 human players--and it's going to be tough to code the game play for that--then you create TWO OBJECTS of class HumanPlayer. You do *NOT* try to put two people into ONE Player.

Old Pedant
12-16-2009, 05:58 AM
And I am not going to write all the main code for you, but let's at least show the biggest problems.

public class TicTacToeTest
{
public static final void main(String[] args)
{
Scanner input= new Scanner(System.in);
TicTacToeBoard bd = new TicTacToeBoard();
ComputerPlayer cp = new ComputerPlayer();
// where do you get the NAME of the human player???
HumanPlayer hp = new HumanPlayer();

System.out.println("Main Menu\n WELCOME TO TIC-TAC-TOE!");
System.out.println();
System.out.println("PLAYER 1 IS ALWAYS X ");
System.out.println();
System.out.println("1. One player game.\n2. Two player game.");
System.out.print("Please Select: ");
int game= input.nextInt();
// YOU HAVE NO CODE HERE THAT DOES ANYTHING WITH THAT IF ANSWER IS 2!
// YOU REALLY OUGHT TO GET RID OF THAT

System.out.println("One Player Game\nWho will go first?\n1. Me.\n2. The Computer.");
System.out.print("Please Select: ");
int choice= input.nextInt();
// AND BECAUSE YOU DON'T HAVE A COMMON BASE CLASS FOR THE
// TWO PLAYER CLASSES, EVEN THIS QUESTION SHOULD BE TOSSED OUT FOR NOW
// MAYBE LATER, AFTER YOU UNDERSTAND THINGS BETTER YOU CAN PUT IT IN
// play the game
while ( true )
{
bd.showBoard();
cp.makeMove(bd); // computer always goes first
if ( bd.isGameTie() || bd.isGameWonBy( cp.getPlayType ) ) break; //out of loop

bd.showBoard();
hp.makeMove(bd); // then the human
if ( bd.isGameTie() || bd.isGameWonBy( hp.getPlayType ) ) break; //out of loop
}
if ( bd.isGameTie )
{
... tie game ...
} else if ( bd.isGameWonBy( hp.getPlayType ) ) {
... human wins ...
} else if ( bd.isGameWonBy( cp.getPlayType ) ) {
... computer wins ...
}
} // end of main
} // end of class

Old Pedant
12-16-2009, 06:03 AM
I guess I did write the main code for you. Oh, well.

Your isGameWonBy is badly broken. Your first 6 lines make no sense whatsoever. You'll just end up doing infinite recursion.

You never bother to check to see if the 3-in-a-row matches the argument (the player's enum that you are testing).

You have nested for loops but never use them.

Toss that code and start over.

mdnealy
12-16-2009, 06:32 AM
nevermind say the last post and yes you actually put my program together...but sure as heck learned alot!!!

Old Pedant
12-16-2009, 06:56 AM
I'm heading for bed.

I'll kick myself in the morning for this, but...


public boolean isGameWonBy( TicTacToeEnum te )
{
for ( int row = 0; row < 3; ++row )
{
if (board[row][0] == te && board[row][1] == te && board[row][2] == te )
return true;
}
for ( int col = 0; col < 3; ++col )
{
if (board[0][col] == te && board[1][col] == te && board[2][col] == te )
return true;
}
if ( board[0][0] == te && board[1][1] == te && board[2][2] == te )
return true;

if ( board[0][2] == te && board[1][1] == te && board[2][0] == te )
return true;

return false;
}

Remember the K.I.S.S. principle.


Now, for your part, see if you can come up with a better strategy for the computer player than simply making a random move.

mdnealy
12-16-2009, 07:57 AM
my board is still screwing up...i will look it over..but I am right behind you it is 2 am here...

btw...now your forum name "Pedant" makes sense...and as far as the first part I am sure I have you beat by far...

More tomorrow...



btw...i am going to have to keep doing projects to learn this java stuff just because...now...

Old Pedant
12-16-2009, 07:04 PM
My age this year is the product of two primes.

My age last year was not prime but had only one prime factor.

My age the year before that was the product of three primes, two of which were the same.

Should be able to figure it out from that.

mdnealy
12-16-2009, 07:41 PM
s@#$....I am finishing up this Java and you throw that...I think I will wait till later tonight when i am drinking this all off to guess that :)

Everything..with the exception of two player is working...........drumroll


GREAT!!!

after i finish i will look at better moves for the computer..right now i am playing around with the two player..again thanks to your previous posts..will post more soon :)

mdnealy
12-16-2009, 07:54 PM
thanks blew off the project..okay well you do have me beat...not by much..

Old Pedant
12-16-2009, 08:05 PM
Heh! The middle clue is the important one. It severely limits your choices.

Old Pedant
12-16-2009, 08:28 PM
Once again, the right answer for two player is the same as the right answer for two computer players is the right answer for allowing players to choose X and O or allowing either X or O to go first: Polymorphism.


protected class Player
{
protected String playerName;
protected TicTacToeEnum x_or_o;

public String getName( ) { return playerName; }
public TicTacToeEnum getPlayType( ) { return x_or_o; }

public void makeMove( TicTacToeBoard theBoard ) { /* do nothing */ }

}
public class ComputerPlayer extends Player
{
// constructor:
public ComputerPlayer( TicTacToeEnum playType )
{
x_or_o = playType;
playerName = "Computer";
}
public void makeMove( TicTacToeBoard theBoard )
{
... code to make a move ...
}
}
public class HumanPlayer extends Player
{
private Scanner input = new Scanner(System.in);

// constructor:
public HumanPlayer( String name, TicTacToeEnum playType )
{
playerName = name;
x_or_o = playType;
}
public void makeMove( TicTacToeBoard theBoard )
{
... code to make a move ...
}
}

Now your game play looks like this:

Player p1, p2;

? 1 or 2 player ?
if ( 1 player )
{
? get name of human player ?
? get choice of X or O
p1 = new HumanPlayer( name, x_or_o_choice );
p2 = new ComputerPlayer( opposite of human's x_or_o_choice );
} else {
? get name of human player ?
? get choice of X or O
p1 = new HumanPlayer( name, x_or_o_choice );
? get name of other human player ?
p2 = new HumanPlayer( name2, opposite of first player's x_or_o_choice );
}
while ( true )
{
show board
p1.getMove()
if ( gameover ) break;
show board
p2.getMove()
if ( gameover ) break;
}
...

Do you see it? Now you can call p1.getMove() or p2.getMove() without knowing which kind of player is making the move! And you can ask p1 or p2 for their name or their x_or_o value again without knowing which kind of player they are.

Not shown there is how you can allow computer player to go first, but that's easy:

... after getting human player into p1 and computer into p2 ...
if ( computer should go first )
{
Player swap = p1;
p1 = p2;
p2 = swap;
}

See? It's ALL so simple once you have polymorphism.

mdnealy
12-16-2009, 08:43 PM
so, would "Player" be a whole other class or would that be considered my test class?


duh looked at it...hmmmmm

mdnealy
12-16-2009, 08:59 PM
even if i wanted to eclipes won't let me make a protect class...hmm I have to go in at 530 tonight...i will ask him what he wants for the second player..

Old Pedant
12-16-2009, 09:15 PM
Again, been writing too much C++ lately. A Java class can't be declared as protected. But its members can. So zap the protected in front of class name but leave it on the members.

Protected means "visible in this class and in subclasses of this class and in other classses in this package, but not visible to outsiders."

A class not declared public is "package private", meaning that all classes in the same package can access it. Since you aren't using packages yet, it realistically means all your classes can access it.

Same with the protected members: since all your classes are in the same (default, unnamed) package, they are really available in all classes, so you can omit protected completely for now.

C++ is a bit more sophisiticated here, in my opinion. But once you start using packages you'll find the Java scheme is adequate for most things.

mdnealy
12-16-2009, 09:47 PM
okay, why can't i just make another class identical to the humanplayer and call it something different and assign it the enum. X that the computer has.

I am trying this and it just ends up in a tie...is it because the enum can only be used in the two...i would have to add another enum like T in the additional human player class...

am I asking this right?

also, i need to put in to play again...do i do a boolean in test?

Old Pedant
12-16-2009, 10:30 PM
If the two classes do not both *derive* from the same Player class (that is "extends Player") then you can't refer to them via the same class name.

Notice that in my code I said:
Player p1;
Player p2;

But then I *assigned* them as
p1 = new HumanPlayer( ... );
or
p1 = new ComputerPlayer( ... );

You could even do:

? is player 1 human?
if ( yes )
{
? get name
? get X or O
p1 = new HumanPlayer( name, xo );
} else {
? get X or O
p1 = new ComputerPlayer( xo )
}
? is player 2 human?
if ( yes )
{
? get name
p2 = new HumanPlayer( name, opposite of xo );
} else {
p2 = new ComputerPlayer( opposite of xo )
}

And so have the computer play itself.

Go read up on polymorphism. Without polymorphism, you don't really have true OO capablities.

Re play again: Why not just ask a question "Play again? 1=yes" and then get the integer answer and, if it is anything other than 1, break out of an infinite loop.
while ( true )
{
... play a game ...
? Play again? 1=yes
if ( answer != 1 ) break; // out of the loop
}

mdnealy
12-16-2009, 11:15 PM
got it.....i think i am going to stick with the duplicate class of human player....This is alot of coding for a class where the feedback was minimal. He is a good guy but 3/4 programmer 1/4 teacher...it just takes time to learn what works for students...I learned more in the last week on this forum than i have 12-16 weeks in the class.

i think i have the same problem with OO that I did in calc...

you can have a problem and when you get a solution, it doesn't always feel like it is finished so my brain is looking for the additional work to finish it. I want to read into it too much instead of looking at it for what it is...so much for my logical mind....and here at 44 I thought that I was getting smarter finishing these classes....:)

Thanks again for all your help...still going to work on making the computer smarter...(in my game)

Old Pedant
12-16-2009, 11:50 PM
You do *NOT* need a duplicate class!!!

There is NO REASON you can't do
HumanPlayer hp1 = new HumanPlayer( "Joe", TicTacToeEnum.X );
HumanPlayer hp2 = new HumanPlayer( "Bob", TicTacToeEnum.O );


The problem comes in the game play: You'll have to be testing *IN THE LOOP* for whether you have one or two humans and ask for moves accordingly.

Probably something like this:
while ( true )
{
...show board...
hp1.getMove();
... if game over break ...
... show board ...
if ( one player game )
{
cp.getMove()
} else {
hp2.getMove()
}
... if game over break ...
}

Oh, okay. Now that I write it out like that I guess it's not such a big deal. It's just crappy coding style, all because you supposedly haven't learned about superclasses/subclasses.

Old Pedant
12-16-2009, 11:52 PM
Actually, I guess you could even allow the user to choose 1 or 2 players and, if one player, *WHICH* player he will be. Then you can do:

while ( true )
{
...show board...
if ( hp1 == null )
{
cp.getMove()
} else {
hp1.getMove()
}
... if game over break ...
... show board ...
if ( hp2 == null )
{
cp.getMove()
} else {
hp2.getMove()
}
... if game over break ...
}

mdnealy
12-17-2009, 01:50 AM
ha ha....it worked for the two human...i just changed the test for the hp1 and hp 2...works great!!! thanks!!!!

I didnt even have to change any code except on the test page..


HumanPlayer hp2= new HumanPlayer("bob", TicTacToeEnum.X);
HumanPlayer hp1 = new HumanPlayer("human",TicTacToeEnum.O);

the input for the names overrode the "bob" and "human" lol how simple was that..duh..

Old Pedant
12-17-2009, 01:55 AM
That's what I've been trying to tell you. And *IF* the two classes--HumanPlayer and ComputerPlayer--were subclasses of Player, then it would be even simpler, yet again.

mdnealy
12-17-2009, 02:15 AM
i added that one line to test and just rearranged some stuff...i could have hit myself in the head...well, now i could and it is getting to the point that I wouldn't feel it...not because of the tequila but because i have been racking my brain for over a week... your coding is what put my program together but while I was waiting I really was sitting at this desk moving things around and trying to get it to work...i truly believe my contacts are now embedded in my eyeballs...

camilinks
01-17-2011, 09:44 PM
i got this problem too. Did anyone resolve issue?

Gox
01-17-2011, 09:58 PM
Which problem? Probably best to start a new thread with your specific problem.