JFrame white and unresponsive with a while loop - java

I am having troubles with programming a game called "Coup" and to explain what the problem is, i need to briefly explain what the game is about. Coup is a card game where players try to eliminate each other and be the last player left. To do this, players can choose a number of actions but they can also lie to other players. In this game, other players can call "bullshit" or block another players action. Because of this, i need to make Response windows which will let other players respond with a challenge, a block or do nothing. The result of the action is then dependent on the responses. For example, a player tries to get foreign aid. I can decide to block his action or to let him continue. There are consequences if i block but that isnt the problem here.
The real problem is this: I want to give all my players a chance to give a response (Block or do nothing) via a JFrame and I use a while loop to wait for all players responses. However, this while loop doesnt do anything except keep the method from progressing since the result depends on players reactions. With the while loop, the JFrame I constructed appears white and doesnt contain the two buttons i made. At this point i can even press the close button and it wont respond due to the while loop I made which is dependent on my responseless window. Is there anyway to fix this?
if (turnCount == players[currentPlayerNum].getPlayerNum()){
for(int i=0; i<players.length;i++){
//If it is not the players turn and they have one or two lives, make response window
if (players[i].getPlayerNum() != turnCount){
if (players[i].getLives() != 0){
//foreignAidBlock constructs the response window
players[i].foreignAidBlock(turnCount);
}
else{
//Not applicable since out of game/not in game
players[i].setResponse("NA");
}
}
else{
//Not applicable since out of game/not in game
players[i].setResponse("NA");
}
}
//Idea: PAUSE TILL RESPONSES COME IN
while(players[0].getResponse() != null || players[1].getResponse() != null || players[2].getResponse() != null || players[3].getResponse() != null)
{
System.out.println(players[0].getResponse());
System.out.println(players[1].getResponse());
System.out.println(players[2].getResponse());
System.out.println(players[3].getResponse());
}
The result i get from running this part of the code is:
"NA
null
NA
NA"
continuously. I use a null to represent a player that hasnt answered yet. At the end of the method, I reset all of my players abilities back to null.
All my response window will do is change the response of the player from null to "B" or "N". But without access to the buttons I cannot do this. Does anybody have any tips on how to use something to "pause" my thread besides using a while loop?

As Abdul Fatir mentioned, it is because the UI thread is being blocked.
I would however not reccomend directly messing with threads. There is a SwingWorker class exactly for this scenario and it is reccommended you use this.
For more info check this blog article - Swing Worker Example
You can also find some useful info in the following SO question - How do I use SwingWorker in Java
Here is quick use example from the official javadoc:
Say we want to find the "Meaning of Life" and display the result in a JLabel.
final JLabel label;
class MeaningOfLifeFinder extends SwingWorker<String, Object> {
#Override
public String doInBackground() {
return findTheMeaningOfLife();
}
#Override
protected void done() {
try {
label.setText(get());
} catch (Exception ignore) {
}
}
}
(new MeaningOfLifeFinder()).execute();

The while loop is blocking your UI Thread. Perform your while loop checks in a different Thread.
Thread t = new Thread(new Runnable(){...});
t.start();
This way your UI won't be blocked and controls will remain responsive.

Related

Using Java's Swing UI to make rock, paper, scissors, lizard, spock

I'm trying to develop a version of rock, paper, scissors, lizard, spock using Java's Swing UI. I've successfully been able to create frames to select player 1 and player 2 and which rules the game is won by (best 2 out of 3, play till quit, single round), and that run the actual game. But I'm having trouble looping the game screen if the user want's to play, say best 2 out of 3. I had originally coded the program just using the console output(Scanner), but now that I am trying to implement the Java Swing UI. And I can't seem to figure out how to loop round after round without producing all of the game screens at once.
For example, here I have a method I call playRound(). After adding 1 to the round counter, this method constructs class GameWindow extends JFrame implements ActionListener
public static void playRound() {
++round; //Simple int counter to keep track of round
GameWindow oneRound = new GameWindow();
oneRound.setSize(400, 150);
oneRound.setLocationRelativeTo(null);
oneRound.setVisible(true);
Inside the GameWindow class, I have 5 ActionListeners on the 5 buttons the user can decide to play(rock, paper, scissors, lizard, or spock). The ActionListeners identify which button was pressed, then triggers the rest of the game logic, as seen below.
#Override
public void actionPerformed(ActionEvent e) {
String move1 = "";
Object source = e.getSource();
if (source == rockBtn) {
move1 = "rock";
} else if (source == paperBtn) {
move1 = "paper";
} else if (source == scissorsBtn) {
move1 = "scissors";
} else if (source == lizardBtn) {
move1 = "lizard";
} else {
move1 = "spock";
}
String move2 = Game.p2.move();
Game.p1.learn(move1, move2);
Game.p2.learn(move2, move1);
this.dispose();
Game.score(move1, move2);
}
I'm fully aware that if I use a while loop along the lines of
while (round < 3)
playRound();
I'm going to get three GameWindows to pop up all at once. Am I stupid, or is there a way to close the window other then this.dispose() and get a new one to trigger/open so the user can play again?
Sorry if this is very sophomoric, but I've been scouring JavaDocs trying to learn the answer. The closest thing I can figure out is that I'm looking for a WindowEvent, but I'm not sure where to place the listener for it, or what action I would need it to trigger. If you just tell me I'm an idiot, I'll go bury my head in the sand and be done with it, but any advice would be greatly appreciated!
If I understood your problem, you want to have three rounds, each time redoing the same logic but keeping the score as a "global variable" for the three rounds, giving user the opportunity to restart again or close entire application after the three rounds are completed.
I'll give you a pratical idea of how I'd make this implemented:
I suggest you to move main coordination logic in a main method, and keep the rest as you posted, with a little modifications.
You can just make your playRound() method returning a ResultDTO object instead of void; this DTO can be a simple POJO object containing all the variables representing the data you want to globally maintain (for example in a ResultDTO[] array with 3 elements, filling one position for each round), filling it in the playMethod()'s logic and managing the return in an external caller main method. After the three rounds you can just check for result in the main method, print out a dialog showing the results you want to show, and then ask user a yes or no option with JOptionChooser. If user wants to play again, just repeat this whole logic, in the other case you can call System.exit(0) to close application or do whatever you want first (save a file with memory data, print a goodbye message, and so on, it depends on your imagination and how you want to implement this, just be creative).
To ensure your application will not close at the end of a round, you can use oneRound.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE) to avoid application exiting when calling dispose() on your frame.

How do action events work with players' turns, need help showing which card the user played before the computer shows what card it played

Im creating an uno game and it is almost fully functional and i'm using javaFX to create it. It is Computer vs User and the problem is that when a user clicks on a card button, the middle card is supposed to be replaced with that card and then the computer goes, however what ends up happening is that the computer goes right away and so you only see the computer's card played in the middle. I am sure this has something to do with how i structured my code specifically the action event pertaining to the button clicked. However, since this is my first ever java GUI and i am fairly new to java i am struggling to understand how to structure it so that i am able to show the user's move. Also due to this, i am unable to implement a skip card even though i have tried using a boolean and creating another method i think the main problem lies within how the main gameloop and the actionevent inside is set up.
This method is called and it checks for a button click and then gets the index of the button in the player's arraylist/hand/ The boolean was my attempt at implementing a skip card but what kept happening is the computer would always play right after the user's move when a skip card was played.
public void gameLoop(){
for(int i =0; i<buttonList.size();i++){
buttonList.get(i).setOnAction((ActionEvent)->{
indexOfHandButton = buttonList.indexOf((Button)ActionEvent.getSource());
humanMakeMove();
if(!isReverseTurn()) {
computerMakeMove();
}
});
}
}
This method used the index given from the gameloop actionevent and makes the actual move in the backend. It then clears the hbox containing the users hands and calls showhumanHand which fills it up with the updated cards and similarily with the middle card. The if statements to try and implement the skip cards have not worked, i have also tried creating a new action even inside the if statement and creating a method or recursively calling humanMakeMove but of course the index will be the same and will cause an error.
public void humanMakeMove() {
String result = human.makeMove(game, theDeck, indexOfHandButton, computer);
if(result.equals("skip")){
setReverseTurn(true);
}
hbHumanHandBtn.getChildren().clear();
hbMiddleCard.getChildren().remove(middle);
middle = generateMiddleCard();
hbMiddleCard.getChildren().add(middle);
showHumanHand();
System.out.println(">>>>>>>>>>>>>>>>>>>>>>>" + buttonList);
System.out.println(result);
if (middleCard.getType() != null) {
if (middleCard.getType().equals("skip") && isReverseTurn()) {
System.out.println(isReverseTurn());
gameLoop();
setReverseTurn(false);
}
}
}
So my main question is how can i restructure this or add something that allows for the user's card to show in the middle before the computer goes right away, i have tried a timer/sleep method too. And my skip card doesnt work but i think that has to do with how i set up my action listener which is messing up two problems. Thank you for reading this and let me know if you have any input!

SnakeGame: How to deal with a interrupt thread and with a deadlock

everyone. I'm doing a game for a programming class that consists in two snakes that walk in a bord in opposite directions. They need to block in
barriers and i use coordination for them to not go against each other. Which means that the second one trying to acess a cell, will need to wait till the first unblocks the cell. I already read a lot of topics in this website and i still didn't find a solution to my problem.
Right now i already have the snakes moving all around the board and blocking in the barriers. My two big issues right e that i appreciate any help are follows ones:
1- There's specific situations, for example, two snakes walking paralell, that when they try to turn the direction towards the other snake they both block and the game
stops there, causing a deadlock. Just one can stop, while the other waits for the first one to unblock the cell. I stil didn't find a solution for the specific issue. If they don't collide
in the direction of each one, there's no problem. One snake waits for the other one to clear the cel.. i already read in here a solution about using a CountDownLatch but don't know how to implement it.
2 When the snakes blocks in a barrier, goes on wait(). Then i make her move again cliking in a cell of the board and the snake needs to recalculate a new way to go to the cell i cliked. Which means i need to change the movement from random to a specific one. The teacher said us to interrupt the thread, make her leave the method she was doing (moveNextCell() ) and recalculte the next movement again.
The problem here is that i can handle the interruption but don't know how to activate the thread again. I read it, and don't know if i interpret it bad, that after a thread it's interrupt, i can't start it again, so i need to make a copy of it. But right now i don't know how i can do it in my code since the new thread would need the actual position, color, etc of the snake.
Right now i'm not able to do both situations.
The cell code ( that blocks the snakes in case of barrier or one snake want to use the other one cell ) is the follow:
public synchronized void reserveCell(Snake snakeID){
this .snakeID = snakeID ;
while (type .equals("Barrier" )){
try {
wait();
} catch (InterruptedException e ) {
// When snake it's blocked and we interrupt it, comes to this part!
Thread. currentThread().interrupt();
snakeID.doSpecificMovement();
}
}
while (inUse ){
try {
wait();
} catch (InterruptedException e ) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
setSnakeID( snakeID);
inUse = true ;
}
The snake code ( that makes it move ) is the follow:
public void run(){
while(!Thread.currentThread().isInterrupted()){
moveNextCell( currentX, currentY); // asks the next cell, if possible adds the cell to the body of snake and updates the GUI
setRandomDirection(); // define the direction of next move.
try {
sleep(gameSpeed);
} catch (InterruptedException e ) {
// TODO Auto-generated catch block
e.printStackTrace();
}
gameOver(); // when the snakes reachs the end of the board finishs
}
}
I would appreciate any help that can make me progress in my work. Thanks for any help!
I'm assuming situations you mention in point #1 look like this:
You cannot do much about it. If snakes are separate threads, they do not know about each other and cannot themselves resolve the conflict. Your professor should specify how to resolve such deadlocks. The simplest solution would be to keep the snakes deadlocked until user interacts and chooses different destination. You can also add timeout to wait() method. If cell doesn't become available after some time, randomly choose different direction.
There are two ways to solve the second issue:
You can stop the thread completely and then start new thread with new destination. You would have to remove InterruptedException from all catches and propagate it up to run() method:
void goToDestination() throws InterruptedException {
...
}
#Override
public void run() {
try {
goToDestination();
} catch(InterruptedException e) {
// end thread
return;
}
}
This way interrupt() will be able to stop the thread. You can restart it like this:
// interrupt and wait until thread actually finishes
snake.thread.interrupt();
snake.thread.join();
// change the destination
snake.destination = newDestination;
// restart the thread
snake.thread = new Thread(snake);
snake.thread.start();
You can also change the destination and interrupt just the main method:
#Override
public void run() {
while(true) {
try {
goToDestination(destination);
} catch (InterruptedException e) {
// try again with changed destination
}
}
}
When user chooses new destination:
// set new destination
snake.destination = newDestination;
// interrupt old goToDestination
snake.thread.interrupt();
banthar, i just tried your second solution and worked great! I would never thought about this, all this exception things it's really a new thing to me!
Like before, i'm gonna say what i did in order to help the others.
As banthar said, all methods that i was using that would lead to the interrupt, i put them going to the run() of the snake. So this way i was able to stop the thread and make a new one. Then i just add to use a method to change the direction and make a new start like banthar put.
Problem solved, thank you very much and hope this can help more people!
About the first issue, i already solved it. In case someone find this useful for their problem, i'm gonna post my solution.
The problem, as Banthar said, is that the snakes don't know about the other ones. Which means that in this specific two situations, they would block each other, waiting for the other to move => Deadlock.
The solution here is for one of them warn the other "Hey Snake, i'm blocked. Don't block waiting for me or we both get stuck".
Searching the internet i found a lot of solutions using a ThreadPool that would coordinate all them but that was just to much for my problem.
So i made a atrribute in Snake called snakeBlocked that turns true whhen the snakes blocks. The operation is made in the Cell when the snake trys to acess it. So when the second snake trys to acess a cell with a snake, the cell have a method to find out what's the value of the snakeBlocked of the snake stuck in the cell. After that turn out easy.
If the snake that wants to acess the cell knows there's a blocked snake there, she changes her direction.
Hope it can help someone since i was stuck in those for a long time.
About the issue #2 gonna try it now, after i come here if i can come to a solution!

Particles system, a delay in an array

I am learning java at the moment and trying to make different features and systems. Right now I am trying to make a really simple particle system, but I have problem.
public void eDelay()
{
try
{
Thread.sleep(17);
} catch (InterruptedException e)
{
e.printStackTrace();
}
}
public void engine()
{
int i = 0;
while (i < particles.size())
{
Particle a = (Particle) particles.get(i);
eDelay();
a.move();
i = i + 1;
}
}
public void actionPerformed(ActionEvent e)
{
engine();
repaint();
}
This is a part of my code where the particles suppose to move. It works fine and they do move, but I want them to move one after another one with a delay(17). However, they move all at once and not one after another.
(particles) is an arrayList with 50 elements in it, each element containst a position for a particle.
(a.move()) is just a movement method where particle moves up.
Don't worry for the rest of the code, the problem is in this part.
Graphics, positioning of the particles, movement of the particles, and other things work fine.
Going to make my comment an answer:
"Don't worry for the rest of the code, the problem is in this part. - Graphics, positioning of the particles, movement of the particles, and other things work fine."`
How can you say this when you know what the cause of your problem is? You could be creating a Swing application (which is part of the rest of the code) and calling Thread.sleep(...) on the event thread. So make no assumptions, tell us all of the story, show more pertinent code, and let's help you solve this.
Edit: I now see that this is in fact a Swing application and so that's likely your problem, although you don't show us where the Thread.sleep is called.Calling Thread.sleep(...) puts the thread that calls it asleep, and if this is the Swing event thread (or EDT), it will put your entire application to sleep -- not a good thing to do. So don't call Thread.sleep on the event thread and use a Swing Timer instead. The tutorials will show you how.
And of course again, don't make any assumptions.
You should call repaint in the engine() loop instead of actionPerformed().
Ok guys, this is actually a bit weird but I just rewrote the engine class again into a for loop and it works.
public void engine()
{
goingcrazy = goingcrazy + gameTimer.getDelay();
for(int i = 0; i < particles.size(); i++)
{
if (goingcrazy > 1000*i)
{
Particle a = (Particle) particles.get(i);
a.move();
}
}
}
I already posted a link for the full code so if you are interested you just need to change the old engine class with the one I just posted.

Alternating images with a timer using java

Since I'm not a CS major, I'm having some difficulties translating my programming wishes into an actual program.
What it basically boils down to is the following: how can I alternate an image on a label, showing each image for an amount of tim specific for each image.
So: say I've images A and B; I'd like the user to see A for 1000ms and B for 200ms. This keeps on looping until a user presses a certain key.
Now, I'm able to load an image onto a panel, quite easily even, and I've managed to catch user input using KeyListener and stuff, which all works quite nicely and alot easier then I had expected. I also know how to use looping constructs like while, for and do..while, but this timer business is shady.
I see all kinds of stuff using threads and what not, I really don't need that. This is not about efficient programming or good code, it's simply about demonstrating something.
Any help would be greatly appreciated!
Use a SwingWorker<Void, Void>. The doInBackground method of the SwingWorker should look like this :
#Override
protected Void doInBackground() {
try {
while (true) {
displayImage(imageA);
Thread.sleep(1000L);
if (isCancelled()) {
return null;
}
displayImage(imageB);
Thread.sleep(200L);
if (isCancelled()) {
return null;
}
}
}
catch (InterruptedException e) {
// ignore
}
return null;
}
private void displayImage(final Icon image) {
SwingUtilituies.invokeLater(new Runnable() {
#Override
public void run() {
// display the image in the panel
}
});
}
The keylistener should simply cancel the SwingWorker.
Here's something that might be a good example:
http://www.java2s.com/Code/Java/Development-Class/UsejavautilTimertoscheduleatasktoexecuteonce5secondshavepassed.htm
I can try to explain the code if it appears confusing
There is nothing necessarily inefficient about using threads when threads are the right tool for the job.
In this case, it would not be unreasonable to create a new class that implements Runnable, which holds a reference to the label you wish to change the image on.
This means that the image could be changed without causing waits on the main application that would cause it to hang until it was done.
You would want to avoid 'Busy Loops' [basically, a while loop with no Thread.sleep() within it], and look to see if there is any needed thread exit criteria

Categories

Resources