• Post Reply Bookmark Topic Watch Topic
  • New Topic

Trying to do a one spot battleship program with computer players.  RSS feed

 
Paul Adcock
Ranch Hand
Posts: 48
Firefox Browser Java Notepad
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I'm trying to do a sort of Battleship program, though, at least for the current version, it will only have one spot.

In the past I've done it with just against a computer where it placed the Battleship and the player guessed until they got it. Now I can do that plus have a two player (er, humans that is) that'll work. However, I've tried threading and Swing Timers for the computer part but it seems to either never fire unless the computer goes first and it sometimes gets caught in an infinite loop and I don't know how to fix it. I had thought that simply calling the run() method of a Runnable or Thread subclass should make it check every so often and keep firing but apparenlty not. So I tried a Swing Timer and had an ActionListener. However, it still is either going into a spot it shouldn't (and hence going into an infinite loop) or only firing once and then disabling the buttons.

Though I don't really want it to be visible long enough, at least for the computer, for an actual human player to mess with it, but I do need a BattleshipFrame object in order for the computer to do the doClick() on one of the buttons, visible or not and I have it disabling the grid, because, unlike for people, I think the computer can call it if I don't disable the grid after one turn and keep firing unless I stop it, whether or not the BattleshipFrame is viisble to the human eye. But the issue seems to be how the heck to fire, disable it until the human player moves, then enable the grid and fire, then disable it until the human player moves, etc.

Here's some code (I don't think you need to see every class I've written. Some I've written for a newer version that will be closer to the full Battleship game though it's in the old project. However, I'm trying to get the simple one square stuff first before going to multi-square.)

























The Player class and HumanPlayer class isn't where the issue is, I just included it for functionality. The same goes for PositionedJButton, PlayerFactory, and ComparablePoint. I just used those either to make things easier or because I needed to alter something from
an exisitng class slightly to meet my needs.


The issue is either in the ComptuerPlayer class, the ComputerThread class, or in BattleshipGUI.

I'm not sure why it doesn't fire at all but seems to go into an infinite loop if the Human player for player vs. Comptuer option goes first and fires once, locks the gird, and you can't go any furhter, though you can resign for the computer as it doesn't get rid of the screen after the human player moves. (If computer goes first, it fires for the computer, hides the computer's screen, shows the player's screen, the player fires, the player's screen is hidden, the computer's screen is shown but wiht the grid disabled and it never fires again, though it DOES let the player resign for the computer, which is NOT what I want either.)

Any idea of what is going wrong?

It's not in placeBattleship() or anything like that.

It's likely in ComputerThread though it could be in BattleshipGUI under the instantiation method that I call for human v. Computer. It most likely isn't the ComptuerPlayer class that's causing the problem, but as that one also could affect what the Comptuer does, I can't rule it out completely. The only other thing that could be causing it is something glitchy in the method in BattleshipFrame that checks to see if it was a miss or a hit or already shot there when it comes to the computer but somehow isn't doing it wrong for the player, just the computer.

 
Jeff Verdegan
Bartender
Posts: 6109
6
Android IntelliJ IDE Java
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Sorry to say, but that is a ridiculous amount of code to post. Since your problem is that you can't get the turns to work properly, start with a fresh program, with no UI other than a single JPanel or JTextField or whatever the simplest thing is you can use to display something.

It should just display something simple, like "Human: 2 turns, Computer 1 turn", and then increment each one appropriately.

Hardcode it to start with the computer turn (or the human, whichever is easier to make work).

There should be no user interaction. It should just mechanically take turns. You may want to put in Thread.sleep() or a Timer or something to simulate delay and make it easier to see it flipping back and forth.

If it's too hard to get the timer working, then try it with a button. Or just read a line from System.in.

Your proof that it works is that the turn counts increase appropriately.

That's the only code you should post here--the simplest turn-taking code you can come up with. No scoring, no ship placement, no hits or misses. Just taking turns.

Once you get that working, you can gradually add other parts of your program back in.

 
Campbell Ritchie
Marshal
Posts: 56541
172
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
When I went through that code wondering whether it ever ended, did I really see empty catch statements for null exceptions (NPE)? That is dreadful design. You should probably let an NPE propagate anyway, because it is almost certainly caused by an error in your programming. And an empty catch is dangerous, because it prevents you finding out about the exceptions.
Did I really see human player and computer player classes? That looks like peculiar design. Human and computer should be instances of the player class, not classes in their own right.
 
Jeff Verdegan
Bartender
Posts: 6109
6
Android IntelliJ IDE Java
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Campbell Ritchie wrote:You should probably let an NPE propagate anyway, because it is almost certainly caused by an error in your programming.


Fixed that for you.

@OP: As you gain experience, you will occasionally find NPEs that are caused by bugs in somebody else's code that you're using, rather than in your own code, and there will be places where it's appropriate to catch them (but probably never to just ignore them). Right now though, I'm willing to bet that probability of either of those happening here is zero. Hence the striking of the qualifiers in what Campbell said.

Did I really see human player and computer player classes? That looks like peculiar design. Human and computer should be instances of the player class, not classes in their own right.


I could see having separate classes inheriting from a common base type:

 
Campbell Ritchie
Marshal
Posts: 56541
172
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Jeff Verdegan wrote:Sorry to say, but that is a ridiculous amount of code to post. . . .
And it has very long lines in, which make it very difficult to read. Please go to the button and break all those long lines. You will find suggestions how to do it here and here.
 
Paul Adcock
Ranch Hand
Posts: 48
Firefox Browser Java Notepad
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
You're right. I don't know those listeners in BattleshipGUI.

Also, now that I think of it, the Player class almost could be an instance. Originally I was going to have the computer place the Battleship outside the player class or do something that just didn't work out. However, a smart computer can remember where it shot and won't fire in the same spot twice. A non-smart computer CAN fire in the same spot more than once. So I DO need a difference for the ComputerPlayer types and can't just have two Player instances.

As for the NPE checks, the thing was, if I had it in single player mode, then there wouldn't be any opposing player and the catch blocks were to catch it instead of throwing a NPE every time getOpposingPlayer() was called. On the other hand, all of the other times there will be two players (or more in tournament mode, which I haven't set up yet.) So, in order for BattleshipFrame to work for both two and single player, I need the try/catch blocks over all calls to getOpposingPlayer() so that it will catch it in the case of a single player but it won't hurt it if it has two players (or more). True, I could just let it throw the exceptions, as it shouldn't, hopefully, crash the program or stop it from working correctly, but I had thought that letting it do that every time in the case of single player mode was also bad design.

Also, my try/catch stuff is so that if the player just hits the X or something when it asks for their name, it won't display null, and, since I set the JFrame title to the player's name, won't throw a NullPointerException later on when I do

jFrame.setTitle(name);

I'm looking over the huge code from above to see if I can isolate the problem areas.



 
Paul Adcock
Ranch Hand
Posts: 48
Firefox Browser Java Notepad
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I think I can rule out ComputerPlayer class or any of the Player classes or subclasses as being the source of the problem. I've cut out the code that isn't the problem (don't whine if it doesn't compile though as I've cut out some important stuff that I can say for certain isn't causing the issue.)


In BattleshipGUI, the only area that could be of issue is this method




As for BattleshipFrame class, the only area of concern I can think of is in the ActionListener that the class implements.




The only thing that could be of issue in the two code samples posted above is that setMovability() or something like that is messing things up for the ComputerThread class.

The most likely place that the error is originating from, or is coming out, is the ComputerThread class, which I'm going to post all of it. (Though I think the issue is sin disableGrid() or the ActionListener.)





 
Paul Adcock
Ranch Hand
Posts: 48
Firefox Browser Java Notepad
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Campbell Ritchie wrote:
Jeff Verdegan wrote:Sorry to say, but that is a ridiculous amount of code to post. . . .
And it has very long lines in, which make it very difficult to read. Please go to the button and break all those long lines. You will find suggestions how to do it here and here.


Ok, down below I've whittled it down to the essential areas. However, you may still need the code up top to get it to compile fully. I've removed some things that will make it not run properly if you just try and compile those snippets by themselves.

I do have it pritning out numbers in the ComputerThread to track where it's going.

It is printing out

1
3
3
3
3
3

etc


if the computer wins the number guessing game it almost seems to work right now. (I'll have to check to be sure.)

However, if the human wins the number guessing game, then it always goes to the fourth thing in the ComputerThread class method but it shouldn't be going there if what I planned was correct.


If the computer is smart, hence will not fire in the same spot twice, then if it goes then it fires and then I fire and then the computer waits and goes into an infinite loop. (Perhaps that might be a result of somehow mistakenly not using parenthesis in the right spot or something. I'll check it out.)

I did find another glitch. It was never stopping the ComputerThread but I fixed that, though it now looks a bit messier in the coding with nested try/catch at some points.

(I needed the nested try catch in the cases that the BattleshipFrame owner in question wasn't a computer and the nested one in case both players were human and hence no ComputerThread.)

 
Paul Adcock
Ranch Hand
Posts: 48
Firefox Browser Java Notepad
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I think I got it solved. By narrowing it down, I happened to check the ComputerThread class and noticed that I was calling a JOptionPane as a verifier if it went into a certain spot. While I'm still not sure why it's going there, it seems to be working now and does what it's supposed to. I also found that I had never stopped the timer after the game ended and fixed that as well.

 
Paul Adcock
Ranch Hand
Posts: 48
Firefox Browser Java Notepad
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
How do I unresolve the thing? It semes to work for Human V Comptuer but when the Comptuer is player 1, Computer V Human, it gets stuck. I've tried all sorts of tweaking.



I have a few new things but see if you can spot the issue in the ComputerThread class as to why it's going astray for Computer vs. Human.

If the computer goes first, then it just sits there and never fires.

It keeps printing out "4".

Also, it keeps the computer grid visible long enough for a human to fire on it or click and resign.

In another case, it is firing though nothing is clicked and nothing was added to the shot count. After firing, somehow I suspect on MY grid, instead of theirs, it stalls out again and let me fire again I think.

 
Paul Adcock
Ranch Hand
Posts: 48
Firefox Browser Java Notepad
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Never mind. It was a typo. I was somehow setting the same name for both players, hence my grid looked exactly like the computer's. I kinda figured it out when I fired for the computer and it said the computer had both won and lost when I sunk a battleship.


Now the only slight issue is that sometimes the popup of "Miss!" or whatever comes up behind the grid and I have to hit spacebar to activate the OK button as the dialog thingy (a JOptionPane) is modal and I can't shrink the grid GUI to get at it therefore. But it only happens every once in a while and is easily resolved by pressing the spacebar.

I don't wanna jump the gun again but it seems this thread is resolved once more.

 
  • Post Reply Bookmark Topic Watch Topic
  • New Topic
Boost this thread!