Thread, while loop and a System.out.print statement - java

Hi guys I have a nested Thread and using it to see when a player has taken a turn (in a draughts game) O have a game object and a public variable changedTurns.
new Thread() {
public void run(){
check();
}
private void check(){
boolean sent = false;
while(true){
System.out.println("ee"); \\line 9
if(game.changedTurns){
System.out.println("gg");
if(!sent){
System.out.println("ok");
sent =true;
}
}
}
}.start();
Everything works as expected like above I.e console shows plenty of "ee" followed by "gg" and then "ok" when the player takes their turn, however without line 9 nothing is shown when the player takes their turn ?!

You don't need to use threading to analyze whether the player has taken a turn. Just create a Player[] array and add a variable turn for the index of the player whose turn it is. Increment turn when a Player makes a turn.

Related

Implementing a simple turn-based game in Java using the wait-notify approach

I'm trying to implement a word game in Java, where each player takes turns extracting a number of random letters from a set, then trying to create a valid word with those letters. This is what I have so far (simplified for clarity's sake):
In the Game class, I start the game by running a thread for each player (and one for the timekeeper). I want the first player in the activePlayers list (which initially is the same as the players list) to make the first move, so I initialized the turn and turnIndex attributes to correspond to this player:
public void play()
{
this.turn = activePlayers.get(0); //the player who joined first goes first
this.turnIndex = 0; //the player's index in the ArrayList
for(Player player : players) {
new Thread(player).start();
}
new Thread(new Timekeeper()).start(); //keeps track of the game's duration
}
In the Player class, I want the players on stand-by to not do anything, and simply wait for the current player to finish their business, hence the first while loop. Then, when a player's turn has ended, I want that thread to yield the monitor to another player's thread and wait its next turn. This is how I decided to approach it:
private synchronized boolean submitWord() throws InterruptedException
{
while(game.turn != this)
{
System.out.println(this.name + " is waiting their turn...");
wait();
}
Thread.sleep(1000);
List<Tile> extracted = game.getBag().extractTiles(wordLength);
if(extracted.isEmpty())
return false; //if there are no more letters to extract, the thread ends its execution
//game logic goes here - creating and validating the word
//after this player is done, the next player makes their move
game.turnIndex++;
if(game.turnIndex >= game.activePlayers.size())
game.turnIndex = 0;
game.turn = game.activePlayers.get(game.turnIndex);
notifyAll();
return true;
}
#Override
public void run()
{
do {
try {
this.running = this.submitWord();
} catch(InterruptedException e) {
System.out.println("Something went wrong with " + this.name + "...");
e.printStackTrace();
}
} while(this.running);
game.activePlayers.remove(this); //the player is now inactive
if(game.winner == this)
System.out.println("Winner: " + this.name + " [" + this.score + " points]");
}
However, when I try to run the program, I get something like this:
Player 2 is waiting their turn...
Player 3 is waiting their turn...
1 seconds elapsed...
Player 1: AERIAL [36 points]
Player 1 is waiting their turn...
2 seconds elapsed...
3 seconds elapsed...
4 seconds elapsed...
5 seconds elapsed...
6 seconds elapsed...
Basically, the game doesn't move past Player 1's first try, and I get stuck in an infinite loop where nothing happens. Am I not using the wait() and notifyAll() methods properly? How should I make the player threads communicate with each other?
If I have understood your code correctly, that submitWord method belongs to the Player class. The keyword synchronized should be used to obtain the monitor of a shared resource to limit different threads from accessing the same resource at the same time and avoid race conditions.
In your case, you're synchronizing over a Player thread which is not the right design. You should synchronize instead over the shared resource which is the game object in this scenario. Besides, try to use synchronized blocks rather than entire synchronized methods, as the latter are more likely to block.
Within the Player's run method you should check whether the thread can acquire the game resource first with a synchronized block, if they do, then you can check whether it's the Player's turn by confronting the turn index of the game object with the Player's index. If it's not the Player's turn it invokes the wait() method; otherwise it carries on with its task by invoking submitWord.
Here, I've tweaked your code. You forgot a notify (or notifyAll) call when you were returning false in your submitWord method. That might have caused some stuck scenarios when there were no combinations available.
//Now, this method can be called only under the condition the the game's monitor lock has been already acquired. So, it can only be invoked within a synchronized block.
private boolean submitWord() {
List<Tile> extracted = game.getBag().extractTiles(wordLength);
if(extracted.isEmpty()){
//notify is more efficient than notifyAll as it causes less overhead by awakening only one random thread instead of all the ones waiting
this.game.notify();
//you were returning without notifying here... This might have caused some stucking scenarios...
return false;
}
//game logic goes here - creating and validating the word
//Rotating the turn
game.turnIndex = (this.game.turnIndex + 1) % this.game.activePlayers.size();
game.turn = game.activePlayers.get(game.turnIndex);
this.game.notify();
return true;
}
#Override
public void run() {
do {
synchronized(this.game){
if (this.game.indexTurn == this.index){
this.running = this.submitWord();
//It's more efficient to check here whether the player must be removed or not as you already own the game's lock
if (!this.running){
this.game.activePlayers.remove(this);
}
} else {
try {
this.game.wait();
} catch(InterruptedException e) {
System.out.println("Something went wrong with " + this.name + "...");
e.printStackTrace();
}
}
}
} while(this.running);
//you should re-acquire the game's lock here since you're modifying the set of players
//synchronized(this.game){
// this.game.activePlayers.remove(this);
//}
if(this.game.winner == this){
System.out.println("Winner: " + this.name + " [" + this.score + " points]");
}
}
Just a thought, but it could be that the sleep is happening within a synchronized method: Thread.sleep is blocking other thread also, working on other method, along with itself callled inside synchronized method

How to wait in java without stopping the entire program

I am making a game where the player can throw up to three projectiles at a time. I'm having trouble with the reloading. Here is the code:
public class AmmoManager {
public void tick(){
if(Player.ammo <= 0){
for(int t = 0; t < 10; t ++){
}
Player.ammo = 3;
}
}
}
It's supposed to wait a bit and then set the ammo to 3, but as soon as the ammo becomes 0, it is set to 3 instantly. What am I doing wrong?
I've tried using sleep, but the entire application would stop.
The problem is that your main program waits for tick() to return something.
Think about it like this; if you have this method
public boolean isOne(int num){
Thread.sleep(1000);
if(num==1){return true;}
return false;
}
and
boolean result = isOne(1);
if(result){ //can't be ran until isOne(1) returns the boolean
//do something
}
You can't continue with you main class when you call isOne() because you dont have the value of the boolean it returns. you have to wait for it to return the value, and then you can continue with the main method
The solution is threading. I'm not an expert on it, so you will need to consult someone else or an online resource, but I think it would look something like this:
public void tick(){
new Thread({ new Runnable(){
#Override
public void run(){
if(Player.ammo <= 0){
Thread.sleep(*seconds* times 1000);
Player.ammo = 3;
}
}).start();
}
There are two problems here.
as soon as the ammo becomes 0, it is set to 3 instantly. What am I doing wrong?
That's because the for loop does nothing. When you enter tick() and Player.ammo is 0, you instantly set it to 3.
I've tried using sleep, but the entire application would stop.
If you only have one thread, that is what Thread.sleep does.
I suspect that what you are attempting is more difficult than you think...
You need a main loop that controls the pace of the game. I might sleep() to ensure that the game does not run too fast.
Each pass, it must instruct every player, or whatever constructs you use, to update themselves. As one of the comments noted, that might involve incrementing a counter to replenish ammo.

LibGDX Do Something One Time During Update Method

I'm a bit new to Java and LibGDX, and I'm working on a point based game. A problem I'm facing is that the update method constantly runs something that I want to run on a timely manner. In my update method, I have the code to increment the score if a point is earned, and to make a lose state come up when the player lost. Without going into much detail, here's the pseudo code I have:
protected void update(float dt){
for(Thing x : a list) {
x.update(dt);
//continue
if (you complete the objective of the game) {
score++;
//do other stuff
}
//lost
if (you fail to complete the objective){
make lose state come up
}
}
//I want something like this to run:
if(score >=0 && score <=10){
do something ONCE(ie. print to console once)
}
if(score >= 11 && score <=15){
do something once
}
if(ect...){
do something else once
}
.
.
.
The problem here is that, if the IF condition is met, I notice the IF block gets executed multiple times very quickly(ie. printing to the console a lot). I have enclosed the details of the code that relies on the score in a separate class, I just want to be able to call the method from this update method and have it run once depending on the score conditions (ie. run it again if the score satisfies another IF statement)
I had the same problem, but I solved it by using following method. In Libgdx the update method runs in 1/60 second. That is the reason the method is rendering continously and the if condition will be executing various times.
To solve this problem, just declare an integer variable, say count, in your create method.
public static int count;
public static void create()
{
count =0;
// do other stuffs
}
protected void update(float dt){
// just increment this count value in your update method
for(Thing x : a list) {
count++
x.update(dt);
//continue
if (you complete the objective of the game) {
score++;
//do other stuff
}
//lost
if (you fail to complete the objective){
make lose state come up
}
}
// and make a small condition to run the if condition only once by using the declared variable "count".
if(count%60==0){
// here the condition only executes when the count%60==0.that is only once in 1/60 frames.
if(score >=0 && score <=10){
}
if(score >= 11 && score <=15){
}
if(ect...){
}
}
.
.
. This is how I solved the same issue.
The update() method is called every frame, multiple times very quickly(usually 60 times per second) in an infinite loop. This is not only specific in libGDX, but in any game engine. And when some condition of your if block evaluates to true, that if block is executed every frame until that condition becomes false again. But you want to execute the block only once after the condition changed.
Just declare a variable named isLastScoreUnder10 or whatever, and update it after the if block. Like this:
private boolean isLastScoreUnder10 = false;
protected void update(float dt){
if(!isLastScoreUnder10 && score >=0 && score <=10){
isLastScoreUnder10 = true;
// ..do something
} else {
isLastScoreUnder10 = false;
}
}

How to loop a Midi sequence Java

I am fairly new to Java programming, and would like to know how to properly loop a MIDI sequence whilst a game is playing. I have some code and I know that I should use setLoopCount() in order to do it but am unsure how to implement it.
Here is the code I have so far
Sequencer myseq;
myseq = MidiSystem.getSequencer();
myseq.open();
File myMidiFile = new File("sounds/music.midi");
Sequence supersequence = MidiSystem.getSequence(myMidiFile);
myseq.setSequence(supersequence);
myseq.start();
Any help is appreciated.
I think this could help you:
myseq.setLoopCount(Sequencer.LOOP_CONTINUOUSLY);
You don't need an external method to loop a Midi Sequence. Based on your code above you should use the following:
import java.io.*;
import java.util.*;
import javax.sound.midi.*;
public class Midiplayer{
public static void main(String[] args) throws InvalidMidiDataException, IOException, MidiUnavailableException {
//Create scanner object
Scanner in= new Scanner(System.in);
//Request Loop Count
System.out.println("How Many Loops?");
int loops= in.nextInt();
//Retrieve the MIDI File
System.out.println("Please type in the exact location of your midi:");
String fileAndLocation= in.next();
Sequence myseq = MidiSystem.getSequence(new File(fileAndLocation));
// Create a sequencer for the sequence
final Sequencer sequencer = MidiSystem.getSequencer();
sequencer.open();
sequencer.setSequence(myseq);
sequencer.setLoopCount(loops);
//Exit message
System.out.println("Press 'ctrl' and 'c' on keyboard simultaneously to end sequence and program.");
// Start playback, repeats automatically
sequencer.start();
//Don't forget to close reader
in.close();
}
}
Do note though that the above does not create an infinite loop. My guess is that you need to set "loops" to 1 and increment it within a while statement that tests like the following:
while(loops>0){
//Start/restart Midi Sequence
sequencer.start();
//increment loops
loops++;
//Re-instantiate .setLoopCount()
sequencer.setLoopCount(loops);
}
If the loop determination is user based, then have the user input 0 in in the place of infinity so that:
if(loops==0){
//Declare and instantiate a boolean to test
boolean infinite=true;
//Make loops equal to 1 so that the later while statement initiates and repeates
loops++;
//Re-instantiate .setLoopCount()
sequencer.setLoopCount(loops);
}
if(infinite==true){
while(loops>0){
//Start/restart Midi Sequence
sequencer.start();
//increment loops
loops++;
//Re-instantiate .setLoopCount(), thus always adding a loop to setLoopCount(), making it infinite because loops will always be greater than zero
sequencer.setLoopCount(loops);
}
}
else{
//Starts sequence and repeats according to defined loop while loops>0 (so long as you have an error cather for loops<0)
sequencer.start();
}
To end the user interface for an infinite loop, at some point remind the user that in COMMAND PROMPT, 'ctrl'+'c' quits the program.
I hope this helps a lot of people (I based it off my own midi program, which works). However, do note that anything about an infinite loop I have not yet tested. It is only theory based on heavy analysis of the situation and the available classes and variables.
Do note that .setLoopCounter() is present in Java 1.4.1 and on.
Thank you and I am glad to help.
There is a good (but old) book about java game development: http://www.brackeen.com/javagamebook/ The source code is available at the website. Check out the chapter 4... In the SoundManagerTest.java file, you will find an example about looping midi sounds. I hope it is not too outdated.
Btw: There seems to be an issue with MIDI looping and Java 5. Have a look at the end of the page:
Sound Issues in Java 5 and Java 6.
Sun updated the sound engine in Java 5 which led to a few problems. Here are the fixes:
MIDI music doesn't loop. Add this line (in bold) in MidiPlayer.java:
public void meta(MetaMessage event) {
if (event.getType() == END_OF_TRACK_MESSAGE) {
if (sequencer != null && sequencer.isOpen() && loop) {
sequencer.setTickPosition(0);
sequencer.start();
}
}
}
Add a listener for the end of the song like this:
myseq.addMetaEventListener(new MetaEventListener() {
public void meta(MetaMessage msg) {
if (msg.getType() == 0x2F) { // End of track
// Restart the song
sequencer.setTickPosition(0);
sequencer.start();
}
}
});
This is also useful if you want to create a playlist and have it continue to the next song.

controlling threads flow

I had a task to write simple game simulating two players picking up 1-3 matches one after another until the pile is gone. I managed to do it for computer choosing random value of matches but now I'd like to go further and allow humans to play the game. Here's what I already have : http://paste.pocoo.org/show/201761/
Class Player is a computer player, and PlayerMan should be human being. Problem is, that thread of PlayerMan should wait until proper value of matches is given but I cannot make it work this way. Logic is as follows: thread runs until matches equals to zero. If player number is correct at the moment function pickMatches() is called. After decreasing number of matches on table, thread should wait and another thread should be notified. I know I must use wait() and notify() but I can't place them right.
Class Shared keeps the value of current player, and also amount of matches.
public void suspendThread() {
suspended = true;
}
public void resumeThread() {
suspended = false;
}
#Override
public void run(){
int matches=1;
int which = 0;
int tmp=0;
Shared data = this.selectData();
String name = this.returnName();
int number = this.getNumber();
while(data.getMatches() != 0){
while(!suspended){
try{
which = data.getCurrent();
if(number == which){
matches = pickMatches();
tmp = data.getMatches() - matches;
data.setMatches(tmp, number);
if(data.getMatches() == 0){
System.out.println(" "+
name+" takes "+matches+" matches.");
System.out.println("Winner is player: "+name);
stop();
}
System.out.println(" "+
name+" takes "+matches+" matches.");
if(number != 0){
data.setCurrent(0);
}
else{
data.setCurrent(1);
}
}
this.suspendThread();
notifyAll();
wait();
}catch(InterruptedException exc) {}
}
}
}
#Override
synchronized public int pickMatches(){
Scanner scanner = new Scanner(System.in);
int n = 0;
Shared data = this.selectData();
System.out.println("Choose amount of matches (from 1 to 3): ");
if(data.getMatches() == 1){
System.out.println("There's only 1 match left !");
while(n != 1){
n = scanner.nextInt();
}
}
else{
do{
n = scanner.nextInt();
}
while(n <= 1 && n >= 3);
}
return n;
}
}
Well, let me first say that I think you are making this hardier than you need to. If it were me, I would create a 'GameMaster' class whose job it is to loop and tell each player when their turn comes up. Your player classes wouldn't have loops, just a takeTurn method. This way you can remove the waiting/notifying behavior from your player classes.
If you wish to keep the design you have, I would still get rid of the wait/notify and use a Semaphore. Check the docs for proper usage, but the gist is that you would remove the suspend/resume methods and have a acquire() call at the top of your loop and release at the bottom. Just make sure fairness is set to true in the constructor, that way you won't have to worry about a player taking two turns in a row by acquiring the semaphore lock twice in a row.
Ok, so I managed to do it without wait() etc.
http://paste.pocoo.org/show/201966/
When you find yourself having to set up communication between threads to synchronize their execution, just so that a specified sequence of events takes place (such as taking turns playing a game), it's a good sign that you may have more threads than you need.
In this case, consider a single thread that executes a takeTurn() method on various extensions of a Player class might make life easier for you. You could make Player an abstract base class that mandates .takeTurn(), then have HumanPlayer and MachinePlayer classes encapsulate the code that makes sense for each type of player inside that method. This should make extension to larger numbers of players relatively trivial as compared to lots of wait() and notify().

Categories