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!
Related
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.
I'm creating a blackJack game in java using swing in netbeans. Cards are dealt out sequentially to a player's multiple hands and the dealer. JLabels with Card images are to jLayerdPanes when each card is dealt. I want to pause briefly after each card is dealt. Currently you just see them all being dealt at once. This is the code for the first four cards being dealt out.
if(hand1.handIsInPlay()==true){
dealCard(jLPaneHand1,hand1);
pause();
}
if(hand2.handIsInPlay()==true){
dealCard(jLPaneHand2,hand2);
pause();
}
if(hand3.handIsInPlay()==true){
dealCard(jLPaneHand3,hand3);
pause();
}
dealCard(jLPaneDealerHand,dealerHand);
And here is the pause method I tried:
public void pause(){
try {
Thread.sleep(1000);
}
catch(InterruptedException ex) {
Thread.currentThread().interrupt();
}
}
Here is a second pause method I tried:
public void pause(){
try {
TimeUnit.MILLISECONDS.sleep(1000);
}
catch (InterruptedException e) {
//Handle exception
}
}
Neither worked as intended. What looks to have happened was that if three hands were in play, then the program summed up 3x1000ms and waited for that length and then dealt all the cards at once.
How can I make the program pause after every card is dealt?
You need to remember that Thread.sleep is called in current thread. In Java with Swing there will be usually at least 2 threads - Main thread and Swing thread - when you trigger an action appropriate listener is called and it's method executed - as long as this method is still run it cannot move on to other tasks like. e.g. redrawing the cards.
So basically you need to move this pause action to some other thread that will order action of drawing a card with e.g. SwingUtilities.invokeLater, then wait for some time, then again order redrawing and so on.
Basically you need to make sure that GUI thread is not blocked and can work all the time, and orders comes from some other thread(s) - and they CAN sleep without bothering the user.
In your case all happens in 1 thread so when you call on sleep GUI thread sleeps and cannot perform any actions like drawing what you wanted it to draw - it patiently waits till you code in Swing thread stops its execution.
EDIT:
Quick example - knowing exact requirements and code would make it act better...
in listener call e.g.:
new Thread(new CardDealing()).start(); // delegates task to the new thread
while the task would look like:
public CardDealing extends Runnable {
// inner data, methods and so on
public void run() {
if(hand1.handIsInPlay()==true){
dealCard(jLPaneHand1,hand1);
pause();
}
if(hand2.handIsInPlay()==true){
dealCard(jLPaneHand2,hand2);
pause();
}
if(hand3.handIsInPlay()==true){
dealCard(jLPaneHand3,hand3);
pause();
}
dealCard(jLPaneDealerHand,dealerHand);
}
public void dealCards(...) {
// this part will be run in a non-gui thread - make sure that
// all calculations and changes in model are made here
SwingUtilities.invokeLater(new Runnable() {
public void run() {
// this will be run in a swing thread
// - make sure that only code dealing directly
// with GUI is called here
guiDealCards(jPane,hand);
}
});
}
}
Of course depending on your requirements CardDealing class might take parameters, contains references to some data and so on - but that's a matter of overall design. Communiction between GUI and working thread should work more or less like this. You might also try invokeAndWait in this particular case - just make sure that pause() is NOT called inside GUI thread (custom Swing components, Runnables that you delegate, paint methods etc).
EDIT 2:
You might find this link helpful - it would help you understanding how Swing works, and why you should divide your logic into at least 2 parts: GUI and non-GUI. Then whatever
isn't related to GUI place directly in dealCards method, while all GUI related stuff in guiDealCards - I don't know what exactly you are doing there so I cannot you that for you.
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.
I'm trying to accomplish something very simple. First, load my layout (main.xml). Then wait 1 second, modify an image, wait 1 second and modify it to a third image. (My end goal is more complex, of course, but I can't even get this to work).
Basically, I get a black screen when the app loads. It stays that way until all the waiting is over, then it shows the final image. Here's my code:
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
ImageCard[0] = (ImageView)findViewById(R.id.imageView11);
Thread.sleep(1000);
ImageCard[0].setImageDrawable(getResources().getDrawable(R.drawable.secondimage));
Thread.sleep(1000);
ImageCard[0].setImageDrawable(getResources().getDrawable(R.drawable.thirdimage));
ImageCard[0] is the image I'm trying to change. It loads in main.xml and shows fine if I remove the rest of the code.
If I change the sleep time to 5000, it then takes 10 seconds before it finally comes away from the black screen and shows the third image. This is how I know it's not just loading slow, but that it's actually waiting.
It's like it's not running sequentially. I'm no java expert, so I'm assuming I'm doing something dumb...
Thanks for any help!
I think you are blocking the UI Thead. Try Handler.postDelayed on a static Handler object.
Ok heres your problem, you can never do a sleep(...) when you are in the UIThread. The UIThread is never suppose to be locked up, it causes a lot of very bad things to happen in android. But there is a very easy way around it, just get off the UIThread and hop back on it when you need to. Heres what i would recommend:
public void onCreate(...)
{
super.onCreate(...);
myActivity.setContentView(R.layout.main);
new Thread(this).start();
}
public void run()
{
try
{
changeLayout(R.layout.main2);
Thread.sleep(5000);
changeLayout(R.layout.main3);
Thread.sleep(10000)
changeLayout(R.layout.main4);
}catch(Exception e){}
}
public void changeLayout(int id)
{
this.id = id;
myActivity.post(new Runnable()
{
public void run()
{
myActivity.setContentView(id);
}
});
}
private int id;
Of course with this example your class must implement Runnable to work. Only the UIThread can access the UI, no other thread can. Thats why you have to hop on and off the UIThread. Hope this worked!
Try adding ImageCard[0].invalidate() when you want it to draw.
I think Hovercraft Full of Eels is pointing you in the right direction. Essentially, you're not doing any multi-threading, you're telling the main thread to wait which means that it never completes the drawing. I'm not sure about Android, but Swing uses double-buffering by default (to avoid screen flashes), but that means that what is drawn, is actually drawn on to a buffer, not the window itself which is why you don't see anything. You could try disabling the double buffering (which Android is likely using) but that could cause other issues.
You might want to actually do multi-threading, or, I'm sure Android likely has a Timer component. If it does, I'd suggest you use it over Thread.sleep or actual multi-threading. Using a Timer you can have it fire an event after one second. That event will execute the other code.
do you have that code in constructor or in init() function? if yes, draw just the first picture and the Thread.sleep() function move after the place which the constructor or the init() function was called from.
then call repaint() function or something.
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