Win a copy of Murach's Java Programming this week in the Beginning Java forum!
  • Post Reply Bookmark Topic Watch Topic
  • New Topic

TicTacToe design using diefferent designs object oriented etc.  RSS feed

 
Sean Paulson
Ranch Hand
Posts: 87
Java
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I made a tictactoe game in java little while back and have been trying to find different ways to write the code (mianly for practice).
The first version i wrote was linear the second used objects, posted here ticTacToe V1 and 2,
The second version is on the last page.

Here is some pesuedo/cut&paste code to get the jist of what i have now.
This game is a two player game on a 3x3 board. (I am going to be adding a GUI and a computer player using the winimax function.)





So the Player class just gets the move and some other user input... I know all this code is messy and not very good ill get to that later here is some of the board class.




So this code works but my main problem with it is that its very messy.
Also some of the functions in Game are just a middle man and the functions and basically do what the Board class already does or should do on its own(same with the Player class).

So this is what i tried:
I tried to change the Player class to PlayerTurn and have it handle methods such as:
private void setPlayerMark()

private()
row = rowMark();
col = colMark();


Then have the Board class handle all the board type functions and shorten the Game class even more. functions such as
  private void markSpotIsOpen()
     private void markSpot()
             
 
Basically the Game class would just be a game loop that changes the players turn and calls players[i].makeMove().
Also this way I could have a HumanPlayer extends PlayerTurn && ComputerPlayer extends PlayerTurn. This way i could add a computerPlayer and different levels of computerPlayer.

The problem is when i tried this(i can post the code if this is confusing) when i would print the board it would only print the other players moves but it would still store both of the players moves.
I am not sure why. I am guessing it is because my Game class had the Player Objects and my Player class had the Board object.
So board only updated to what ever was currently in the player class and not the currentPlayerObject.
I still don't understand why it would store both the players moves but when printBoard was called it would only show the other players moves.
Wouldnt the row and col ints in Player be what ever the Active player move is. Then it should also still update the boardObj the same way and print both moves especially if it was storing both the moves anyway....:/

To fix this i would have to move the board object to the Game class, in doing this the Game class needs the functions it had before that temporarily store the players moves in activePlayer
and basically create duplicate functions in the Player and Board class's and create the same messy code as before.

So some other options i thought of was 1: using STATE ENUMS and a switch statement in Game(i dont know much about ENUMS though) and have class's Game, PlayerTurn, Board and ComputerPlayer extends PlayerTurn.
2: i could have a helper class..
3: the only other way I could think of is using some kind of Interface Class (ive been reading about and seems like it could work. )

PS is it possible to create a playerObj in its own class of Player? Or maybe create a HumanPlayer Object in PlayerTurn and a boardObj in PlayerTurn.
Then the Game class would have a small loop that calls PlayerTurn Obj.makeMove and PlayerTurn would have a short loop, enterPlayerMove() do boardObj.markIfValid(); while(!validMove).


Well i hope this makes seance, any help getting me over this learning curve using game STATES or Interfaces or object oriented programming in general
would be very helpful, Thanks!

 
Junilu Lacar
Sheriff
Posts: 10929
158
Android Debian Eclipse IDE IntelliJ IDE Java Linux Mac Spring Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
No, it doesn't really make a lot of sense if we don't see actual code. None of what you posted was real code though. And yes, even the fake code you posted was messy so if you say the actual code is messy, I'll take your word for it.   Post it anyway, but only post enough parts that can give context to further discussion. Please don't post 200 lines of messy code because we'll be here until Spring.
 
Junilu Lacar
Sheriff
Posts: 10929
158
Android Debian Eclipse IDE IntelliJ IDE Java Linux Mac Spring Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Sean Paulson wrote:I am guessing it is because my Game class had the Player Objects and my Player class had the Board object.

Guessing at what's wrong with your program is about as effective as forecasting next week's weather by reading chicken bones and tea leaves.

You have to fully understand what's going on; you can't guess. Investigate, analyze, experiment, isolate, and eliminate possible causes of the problem. A systematic and logical approach is the only way to find what's wrong.
 
Sean Paulson
Ranch Hand
Posts: 87
Java
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Junilu Lacar wrote:
A systematic and logical approach is the only way to find what's wrong.



believe me i am. Im just  tired of loooking at it and thought if someone wanted to they could suggest some ideas.

Basically instead of having a Game class with a while loop, and a player class and Board class

id like to try another way ie, ENUMS, interface or a Game class and a PlayerTurn that handles a entire current players turn.
Otherwise the game class handles all the functions and also creates duplicate functions from the Board class and player turn only stores the name, symbol and the players move.
 
Sean Paulson
Ranch Hand
Posts: 87
Java
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Sean Paulson wrote:believe me i am.


Also im not really looking for someone to fix my code just if they have other ways to Design the game. I always see ppl use the Game Player and Board design.
 
Junilu Lacar
Sheriff
Posts: 10929
158
Android Debian Eclipse IDE IntelliJ IDE Java Linux Mac Spring Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Well, it's hard to say anything based on nebulous descriptions. That's like asking a mechanic to tell you if there's anything wrong with your car by letting him listen to the engine over the phone. Show us some relevant parts of the code that you think are particularly troublesome. In other words, pop the hood and let us see what's going on in there.
 
Junilu Lacar
Sheriff
Posts: 10929
158
Android Debian Eclipse IDE IntelliJ IDE Java Linux Mac Spring Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
This doesn't make any semantic sense to me: "I could have a HumanPlayer extends PlayerTurn && ComputerPlayer extends PlayerTurn. This way i could add a computerPlayer and different levels of computerPlayer."

The name "PlayerTurn" does not fit any sensible definition of the idea of "a generalization of a Human Player" or "a generalization of a Computer Player".  That's what the phrase "HumanPlayer extends XXX" should convey. If you had kept the name as "Player" and said "a ComputerPlayer extends Player" and "a HumanPlayer extends Player" instead, that would make perfect sense.

Why did you feel you needed to change "Player" to "PlayerTurn"?
 
Junilu Lacar
Sheriff
Posts: 10929
158
Android Debian Eclipse IDE IntelliJ IDE Java Linux Mac Spring Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
To give you an analogy, saying that "HumanPlayer extends PlayerTurn and ComputerPlayer extends PlayerTurn" is like saying "SpaceShuttle extends RocketLaunch and SpaceX extends RocketLaunch". Surely, that can't make sense to you either.
 
Sean Paulson
Ranch Hand
Posts: 87
Java
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Junilu Lacar wrote:
Why did you feel you needed to change "Player" to "PlayerTurn"?


I see what you are saying and i agree, It just seems like the game class has a lot of unnecessary code and duplicate.

For example in the while loop it where it says do{setPlayerMove();} while(!isvalidMark();) then it calls markSpot.
Well all isValidMark does is call bordObj.isSpotOpen(row, col) then the Board class checks then returns ture or false to Game then game calls markSpot()
and all that does is markSpot(){boardObj.markBoard(row, col)

So basically I am trying to have the while loop only call markSpot then have PlayerTurn do{setPlayerMove()} while !isValidMove and
have only the board handle board functions itself instead of Game handling most everything.
 
Sean Paulson
Ranch Hand
Posts: 87
Java
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Sean Paulson wrote:unnecessary code and duplicate.


Edit: unnecessary and duplicate code.
 
Junilu Lacar
Sheriff
Posts: 10929
158
Android Debian Eclipse IDE IntelliJ IDE Java Linux Mac Spring Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Sean Paulson wrote:
For example in the while loop it where it says do{setPlayerMove();} while(!isvalidMark();) then it calls markSpot.
Well all isValidMark does is call bordObj.isSpotOpen(row, col) then the Board class checks then returns ture or false to Game then game calls markSpot()
and all that does is markSpot(){boardObj.markBoard(row, col)

So basically I am trying to have the while loop only call markSpot then have PlayerTurn do{setPlayerMove()} while !isValidMove and
have only the board handle board functions itself instead of Game handling most everything.

You are making it really hard to follow this conversation; too much work trying to lay out this code properly while reading it. If you posted code that's properly formatted, you'd make this conversation a lot easier to follow. As it is now, it's like you're telling me to read a passage from "Alice in Wonderland" in a bowl of alphabet soup. Please be nice and post some properly formatted code.
 
Sean Paulson
Ranch Hand
Posts: 87
Java
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
God wish i could edit Post.

I guess i could just change it to 


Maybe im just trying to over do the "make it object oriented"

Just seems like it would be nice to have it

 
Junilu Lacar
Sheriff
Posts: 10929
158
Android Debian Eclipse IDE IntelliJ IDE Java Linux Mac Spring Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
1. You really need to work on formatting your code properly. As you posted it just now, that code formatting is atrocious.

2. None of those alternatives seem particularly clear or good to me.
 
Sean Paulson
Ranch Hand
Posts: 87
Java
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Junilu Lacar wrote:
Why did you feel you needed to change "Player" to "PlayerTurn"?


Sean Paulson wrote:
I see what you are saying and i agree, It just seems like the game class has a lot of unnecessary code and duplicate.
For example in the while loop where it says do{setPlayerMove();} while(!isvalidMark();) then it calls markSpot.



Sean Paulson wrote:
Well all isValidMark does is call bordObj.isSpotOpen(row, col) then the Board class checks then returns ture or false



It seems like i shouldnt have to have isValidMark() and i should just be able to call boardObj.isSpotOpen() from the while loop in the Game class.

Im just calling a function that does not do anything but call a function.


Sean Paulson wrote:
then game calls markSpot()
and all that does is markSpot(){boardObj.markBoard(row, col)




Sean Paulson wrote:
So basically I am trying to have the while loop only call markSpot then have PlayerTurn do{setPlayerMove()} while !isValidMove and
have only the board handle board functions itself instead of Game handling most everything.


 
Junilu Lacar
Sheriff
Posts: 10929
158
Android Debian Eclipse IDE IntelliJ IDE Java Linux Mac Spring Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Sean Paulson wrote:
I guess i could just change it to 


Maybe im just trying to over do the "make it object oriented"

This isn't even that object-oriented. Why would isValidMove() accept the row and column as separate arguments? I think I already went over this idea in the previous thread where you had your original effort to write this program but one goal of object-orientation is abstraction. Abstraction means hiding details. Passing in a row and column to represent a "move" is not hiding details; it's revealing details.  Object-oriented code might look more like this:

That code only reveals intent, not implementation. So, instead of revealing that a move consists of a row and column, that implementation detail is hidden behind the abstraction of a "Move" that the expression player[i].move() represents.
 
Sean Paulson
Ranch Hand
Posts: 87
Java
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Junilu Lacar wrote:




So board.isValidMove would first call player[i].move()

then the move() function would return col and row directly to the Board class, instead of returning row and col to the Game class first?
 
Sean Paulson
Ranch Hand
Posts: 87
Java
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Sean Paulson wrote:
then the move() function would return col and row directly to the Board class, instead of returning row and col to the Game class first?


Well if this is true I didnt know I could do this. I think im just trying to move to fast and need to spend more time testing different subjects.
Such as what all can i do with objects and such.
 
Junilu Lacar
Sheriff
Posts: 10929
158
Android Debian Eclipse IDE IntelliJ IDE Java Linux Mac Spring Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Sean Paulson wrote:
Junilu Lacar wrote:


So board.isValidMove would first call player[i].move()

then the move() function would return col and row directly to the Board class, instead of returning row and col to the Game class first?

Sure. If this code is in the Game class, it reflects a conversation between objects that goes something like this:

Game: hey, Board, is this player's move valid?

Board: (behind the scenes) Ok, let me check... The move has a row of ... and a column of ..., now, let me see if that spot is open... yup/nope it is/isn't open.

Board: Hey, Game, I checked and it is/isn't a valid move.

Think of it like buying something from Amazon. Amazon ships your purchase in a box via a courier service, maybe the US Postal Service. The USPS delivers the box to your doorstep and you open the box to make sure you got everything you ordered. Amazon is like a player. The USPS would be like the Game. You would be the Board. Now, you wouldn't want the USPS to open your box and check what's inside right? In most cases, that would be inappropriate. Likewise, it would be inappropriate in an object-oriented sense for a Game to bust open a Move object and drag out its component row and column parts. Why? Because a Game has no real interest in those details. The Game only has an interest in coordinating player Moves and checking the results of how those Moves affected the Board.

Each object in an object-oriented program has its own responsibilities and those should be tied directly to the data that it manages.  If something else manages the data, then an object has no business looking or knowing about the details of that data.
 
Junilu Lacar
Sheriff
Posts: 10929
158
Android Debian Eclipse IDE IntelliJ IDE Java Linux Mac Spring Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Sean Paulson wrote:
Sean Paulson wrote:
then the move() function would return col and row directly to the Board class, instead of returning row and col to the Game class first?


Well if this is true I didnt know I could do this. I think im just trying to move to fast and need to spend more time testing different subjects.
Such as what all can i do with objects and such.

You can do anything you can imagine. The only question is, does it make sense (in terms of object-orientation) to do it that way.  You have to study what object-orientation means. There are principles that will guide you in determining what makes sense and what doesn't.  Abstraction, assignment of responsibility, separation of concerns, SOLID, DRY, SLAP, GRASP design principles.  I've already pointed out all these things to you before. If you really want to learn about object-orientation, you have to dig into those subjects and understand how they affect your design decisions.
 
Junilu Lacar
Sheriff
Posts: 10929
158
Android Debian Eclipse IDE IntelliJ IDE Java Linux Mac Spring Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Sean Paulson wrote:id like to try another way ie, ENUMS, interface or a Game class and a PlayerTurn that handles a entire current players turn.

There are certainly opportunities to define more abstractions using an enum type. A Mark enum, for example, might define the values of X and O or CROSS and NOUGHT. I'm still not convinced that an interface is necessary nor that a PlayerTurn is a legitimate entity that deserves to be represented as a full-blown object. I see no reason why a Game should not be responsible for tracking which player's turn it is to move.

When trying to get an broad overall picture of an object-oriented program's design, I find it helpful to start by identifying some candidate classes and their responsibilities/capabilities. These will suggest what kind of information/data the classes will be responsible for managing and what kind of interactions classes will have with each other (collaboration) -- this is a technique called Class-Responsibility-Collaboration

Board
=> represents the current state of the TicTacToe board
=> can tell whether or not someone has won, e.g. hasWinner()
=> can tell whether or not there are any moves left to make, e.g. hasAvailableMoves()
=> can give a list of available moves left, e.g. getAvailableMoves()
=> can tell whether or not a move is valid, e.g. isValid(Move)
=> can tell which player has moved on a particular spot, e.g. whoMade(Move)

Move
=> represents a position on the board that a Player wishes to mark
=> reifies row and column values on the board

Player
=> provides moves.
=> HumanPlayer will get input from user
=> ComputerPlayer might have "intelligence" and be able to calculate optimal move based on a Game Tree

Game
=> controls overall flow of the round of TicTacToe
=> coordinates actions between Players and the Board
=> reports results of a round
=> tracks whose turn it is to make a move
 
Sean Paulson
Ranch Hand
Posts: 87
Java
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Junilu Lacar wrote:
There are certainly opportunities to define more abstractions using an enum type.


Yeah I agree i will probably keep the classes the way they are. Also tighten up(get rid of some of the middle man functions) the while loop in the Game class.
Then have enums in class Board. enum gameStates WON, TIE, ENDINERROR;

For now I think i will just make a simple program and mess around with objects, enums and ect. To make sure I have a better grasp on everything. 
 
Junilu Lacar
Sheriff
Posts: 10929
158
Android Debian Eclipse IDE IntelliJ IDE Java Linux Mac Spring Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Those middlemen functions as you call them serve one important purpose: abstraction. They may seem like unnecessary hops but they're really there to hide implementation details behind intention-revealing names. Sure, you can move the single lines of code in those methods back to the main flow but then your main flow will no longer have a Single Level of abstraction but instead have a mix of high-level abstractions and low-level detailed code. That is not good.
 
Sean Paulson
Ranch Hand
Posts: 87
Java
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Junilu Lacar wrote:Then your main flow will no longer have a Single Level of abstraction


So then changing the while loop to this



does not count as single level abstraction?
Doing this I have almost half the code i did before in my Game class and a little less in my Board class.
 
Campbell Ritchie
Marshal
Posts: 54886
155
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
You have several layers of nesting there. You have a nesting for the whole game, then one for a single move, and a third level of nesting for am attempt at a move; does that answer your question?
As for valid moves, work out from the rules what is a valid move and what isn't. If you have an invalid move, throw an exception.
 
Junilu Lacar
Sheriff
Posts: 10929
158
Android Debian Eclipse IDE IntelliJ IDE Java Linux Mac Spring Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Lines of code is not a measure code quality. Fewer is not necessarily better. That code is again atrociously formatted. I don't understand what it's doing and I'm not inclined to lose more brain cells trying to figure out the correct structuring. If you want any more feedback from my end, you'll have to do me the courtesy of formatting your code. Otherwise, good luck.
 
Sean Paulson
Ranch Hand
Posts: 87
Java
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Junilu Lacar wrote: I'm not inclined to lose more brain cells trying to figure out the correct structuring.

Well ok then
 
  • Post Reply Bookmark Topic Watch Topic
  • New Topic
Boost this thread!