Storing Blocks for Replace Later - java

Here's my snippet of code. I have Lists for the blocks and player. All I need is for after the five seconds in that runnable is up, it'll replace the blocks that were previously replaced, assigning a player to get the blocks.
#EventHandler
public void onSnowballHit(ProjectileHitEvent e) {
// If it's a snowball...
if (e.getEntity() instanceof Snowball) {
Snowball snowball = (Snowball) e.getEntity();
final Player p = (Player) snowball.getShooter();
// ...if a player threw it...
if (snowball.getShooter() instanceof Player) {
// Make a Player from the Entity
BlockIterator iterator = new BlockIterator(e.getEntity().getWorld(),
e.getEntity().getLocation().toVector(), e.getEntity().getVelocity().normalize(),
0.0D, 4);
// Make a block
Block hitBlock = null;
// Loop through possible blocks
while (iterator.hasNext()) {
// Set the hitBlock to the current block we're checking
hitBlock = iterator.next();
// If it's not air, STOP!
if (!hitBlock.getType().equals(Material.AIR)) {
break;
}
}
int min = 1;
int max = 15;
Random r = new Random();
byte clayBlocks = (byte) (r.nextInt(max - min + 1) + min);
paintBlockList.add(hitBlock);
painters.add(p);
// Set it to stained clay
hitBlock.setType(Material.STAINED_CLAY);
// red = 14, blue = 11 (data values)
hitBlock.setData(clayBlocks);
Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(this, new Runnable() {
public void run(){
if(painters.contains(p)){
painters.remove(p);
}
}
}, 100);
}
}
}

You could do it the same way you remove the Player from the painters list. Once you've found the first solid block (hitBlock) create a new final reference so that you can access it in the Runnable, for example like this:
final Block solidBlock = hitBlock;
To return the block to the state it was before you changed its type and data, you could keep track of those attributes:
final byte previousData = solidBlock.getData();
final Material previousType = solidBlock.getType();
Then in your run() method you can simply change the block back if it is still at that point different like so:
if (solidBlock.getType() != previousType) {
solidBlock.setType(previousType);
}
if (solidBlock.getData() != previousType) {
solidBlock.setData(previousData);
}
I'm sure there's a cleaner, nicer way to do it but this might be good enough for your purposes (I did find a glitch where if you throw two snowballs at the same block, it won't revert to the true original block but to a stained clay block because of the way the future Runnable tasks are written here, to fix this you'd need to write this completely differently and keep track of more things).

Related

How to switch between the classes, in JavaFX?

I have a game template which has two classes as its levels.
The game has a player, enemies, treasure chests, and walls.
When I run the program, it loads Level 1, successfully. I have designed the code so if a certain condition is met, Level 2 must load. Now, Level 2 loads. But certain elements from Level 1 remain on screen, ignoring certain elements from Level 2.
To be exact:
From Level 2, it loads the player's initial coordinates, the treasure chests, and the final destination, ignoring the enemies and the walls.
It brings with itself from Level 1 to Level 2: the walls, the treasure chests, and the enemies. The latter two are in a frozen state. They don't function.
//Instance variables:
private int lvlCount = 1;
// Game() method
public Game(Stage stage) {
this.score = new SimpleIntegerProperty(0);
this.mobs = new ArrayList<>();
this.hitBoxes = new ArrayList<>();
this.treasure = new ArrayList<>();
this.newLevel = new ArrayList<>();
this.enemyCount = 0;
bg();
loadLevel(1);
living();
stuff();
mob2();
finalText();
stage.setOnShown(e -> this.run());
}
//The switch for loading the Levels:
void loadLevel(int in) {
switch (in) {
case 1:
this.level = new Level1();
break;
case 2:
this.level = new Level2(); // placeholder for second level
break;
}
hitBoxes.clear(); // clear the list of hitboxes
mobs.clear(); // remove any existing old mobs
this.getChildren().addAll(hitBoxes); // add all the hitboxes for the walls to the scene
background.setImage(level.getImage()); // get the background image
hitBoxes.addAll(level.getWalls()); // get all the wall hitboxes
enemyCount = level.getEnemyCount(); // get the enemy count from the level
chestCount = level.treasureCount(); // get the treasure count from the level
this.initTreasure(chestCount); // add the treasure chests for the level
this.initMobs(enemyCount); // initialize our mobs
lvlCount = level.lvlCount();
this.initLevel(lvlCount);
}
//The collision check:
private void collisionCheck() {if (r.getFill().equals(Color.WHITE)){lvlCount--;}
//Main Game loop method:
private void play() {
AnimationTimer gameLoop = new AnimationTimer() {
public void handle(long arg0) {
for (int i = 0; i < mobs.size(); i++) {
MOB m = mobs.get(i);
if (m instanceof Enemy) {
((Enemy) m).moveCheck(arg0);
}
}
collisionCheck();
if (lvlCount == 0){
loadLevel(2);} //The condition that loads Level 2
gameLoop.start();
}
Please help me to figure out how I can load Level 2, successfully.
Please note that it does not produce any errors in the console. So, I am having a very hard time figuring out where the problem lies.
I only pasted the code that I thought is necessary to achieve my goal. Here you can see the full code, for veiwing purposes only, no download necessary:
http://paste.mooc.fi/955c6d30
Thank you very much in advance.

Java - Loop gets executed, but header doesnt fit condition

This function should check if the explosion hit a box and should be canceled on the first box it hits.
For example bsp.getBomb().getStrength() is currently 2, when a box is hit i=3, but the loop is executed one more time even if the condition isn't met, why is that?
public void detectBomb(BombSpritePair bsp) {
for(int i = 0; i <= bsp.getBomb().getStrength(); i++) {
if(bd.detect(bsp.getBomb().getX(), bsp.getBomb().getY()+i)) {
Sprite sprite = new Sprite(new Texture("gras.png"));
sprite.setPosition(bsp.getBomb().getX()*16, (bsp.getBomb().getY()+i)*16);
// i = bsp.getBomb().getStrength()+1;
sprites.add(sprite);
System.out.println("RIP"+i);
System.out.println(bsp.getBomb().getStrength());
break;
}
}
}
Try adding break to the loop:
public void detectBomb(BombSpritePair bsp) {
for(int i = 0; i <= bsp.getBomb().getStrength(); i++) {
if(bd.detect(bsp.getBomb().getX(), bsp.getBomb().getY() + i)) {
Sprite sprite = new Sprite(new Texture("gras.png"));
sprite.setPosition(bsp.getBomb().getX()*16, (bsp.getBomb().getY()+i)*16);
sprites.add(sprite);
System.out.println("RIP"+i);
System.out.println(bsp.getBomb().getStrength());
break;
}
}
}
You may be seeing duplicate print statements if you are calling the detectBomb method multiple times. Putting a breakpoint or print statement at the beginning of this method will help determine what the problem is.
Another thing to keep in mind is that you are creating a new Texture for the Sprite every time the method get executed - it would be wise to only instantiate the Texture once and share it with all subsequent Sprite instances that require it.

Setting the block underneath any player to glowstone, then setting it back to the original material

I'm making a Bukkit plugin that will change the block underneath any player to glowstone.
The scheduler isn't working. The ground will change to glowstone but the glowstone block won't revert back to what it originally was.
#EventHandler
public void onStep(PlayerMoveEvent pme) {
Player player = pme.getPlayer();
Location locUnderPlayer = player.getLocation();
locUnderPlayer.setY(locUnderPlayer.getY() - 1);
Location locForScheduler = player.getLocation();
locForScheduler.setY(locForScheduler.getY() + 1);
final Material materialForScheduler = locForScheduler.getBlock().getType();
Block block = locUnderPlayer.getBlock();
Material m = player.getItemInHand().getType();
if (m == Material.GLOWSTONE) {
if (block.getType() != Material.AIR && block.getType() != Material.WATER && block.getType() != Material.STATIONARY_WATER && block.getType() != Material.LAVA && block.getType() != Material.STATIONARY_LAVA && block.getType() != Material.REDSTONE_WIRE && block.getType() != Material.REDSTONE_COMPARATOR && block.getType() != Material.REDSTONE_TORCH_ON && block.getType() != Material.REDSTONE_TORCH_OFF) {
block.setType(Material.GLOWSTONE);
Bukkit.getScheduler().scheduleSyncDelayedTask(Magic.getInstance(), new Runnable() {
public void run() {
block.setType(materialForScheduler);
}
}, 1 * 10);
}
}
}
To get the block underneath a player, you could use:
Block block = player.getLocation().subtract(0, 1, 0).getBlock();
Which gets the player's location, subtracts 1 from the Y-axis, and then gets the block (hence getting the block under the player).
Then to get the type, you could use block.getType():
Material type = block.getType();
To set the block to glowstone, you could use block.setType(Material):
block.setType(Material.GLOWSTONE);
So, if you wanted to set the block under a player to glowstone, then immediately turn it back to the original block, you could use:
Block block = player.getLocation().subtract(0, 1, 0).getBlock(); //get the block
Material type = block.getType(); //get the block's type
block.setType(Material.GLOWSTONE); //set the block's material to glowstone
block.setType(type); //set the block's material back to the original material
But to have a delay between setting the block to glowstone then setting it back to the original block (in your case, the delay is 10 ticks) you could use a Runnable task:
final Block block = player.getLocation().subtract(0, 1, 0).getBlock(); //get the block
final Material type = block.getType(); //get the block's type
block.setType(Material.GLOWSTONE); //set the block's material to glowstone
Bukkit.getScheduler().runTaskLater(Magic.getInstance(), new Runnable(){
public void run(){
block.setType(type); //set the block back to the original block
}
},10L);
We would want to make sure that the block beneath the player is not already glowstone, to insure that the block change does not become permanent. This could be done using simply:
if(!type.equals(Material.GLOWSTONE))
If we did not check for this, then a player could move with glowstone in their hand, hence setting the block underneath them to glowstone, and then starting a timer to set it back to the original block. But, if the player moves while the timer is in session (for example, 5 ticks after they last moved), the block underneath them would permanently change to glowstone.
So, your code could look something like this:
#EventHandler
public void onStep(PlayerMoveEvent pme) {
Player player = pme.getPlayer(); //get the player in the event
final Block block = player.getLocation().subtract(0, 1, 0).getBlock(); //get the block
final Material type = block.getState().getType(); //get the block's material
if(!type.equals(Material.GLOWSTONE)){//don't change the block if it's already glowstone
if(player.getItemInHand() != null){//make sure the item in the player's hand is not null, to avoid a null pointer
Material m = player.getItemInHand().getType(); //get the item in the player's hand
if(m == Material.GLOWSTONE){ //check if the item in the player's hand is glowstone
if(type != Material.AIR && type != Material.WATER && type != Material.STATIONARY_WATER && type != Material.LAVA && type != Material.STATIONARY_LAVA && type != Material.REDSTONE_WIRE && type != Material.REDSTONE_COMPARATOR && type != Material.REDSTONE_TORCH_ON && type != Material.REDSTONE_TORCH_OFF){
block.setType(Material.GLOWSTONE);//set the block type to glowstone
Bukkit.getScheduler().runTaskLater(Magic.getInstance(), new Runnable() {
public void run(){
block.setType(type); //set the block type back to the original type
}
},10L);
}
}
}
}
}
Also, you could reduce this if statement:
if(type != Material.AIR && type != Material.WATER && type != Material.STATIONARY_WATER && type != Material.LAVA && type != Material.STATIONARY_LAVA && type != Material.REDSTONE_WIRE && type != Material.REDSTONE_COMPARATOR && type != Material.REDSTONE_TORCH_ON && type != Material.REDSTONE_TORCH_OFF)
into simply type.isSolid():
if(type.isSolid())
#EventHandler(priority = EventPriority.MONITOR)
public void onMonitor(PlayerMoveEvent event) {
if (!event.isCancelled()) {
Player player = event.getPlayer();
if (player.getItemInHand().getType() == Material.GLOWSTONE) {
Block block = event.getTo().subtract(0D, 1D, 0D).getBlock();
Material type = block.getType();
if (type.isSolid()) {
if (!Restore.locked.contains(block)) {
Restore restore = new Restore(block, type, block.getData());
block.setType(Material.GLOWSTONE);
restore.runTaskLater(Plugin, 10L);
}
}
}
}
}
public class Restore extends BukkitRunnable {
public static Set<Block> locked = new HashSet<Block>();
private Block block;
private Material type;
private byte data;
public Restore(Block block, Material type, byte data) {
this.block = block;
this.type = type;
this.data = data;
locked.add(block);
}
#Override
public void run() {
block.setType(type);
block.setData(data);
locked.remove(block);
}
}
The issue is because you are not checking if the block is already glowstone. So if you are running a temporary glowstone through the code, it will become permanent.
EDIT: Late huh, my bad well I guess anyone else could use it
There's another option:
1) get block under player
Block block = (player.getWorld, player.getLocation().getX(),
,player.getWorld, player.getLocation().getY()-1,
,player.getWorld, player.getLocation().getZ());
2) get the block and save it as a block state
Blockstate bs = block.getState();
3) set the block to glowstone
block.setType(Material.GLOWSTONE);
4) this reverts it back to its last saved state
bs.update(true)
5) (if you want) create a delay
Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(this new Runnable() {
public void run() {
//put delayed code here
bs.update(true);
}
}, 20 * seconds);

libgdx-Actions create stuttering

I try to improve the movement of my figures but i dont find the real reason why they stutter a bit. I am moving them with an SequenceAction containing an MoveToAction and an RunnableAction that does reset the moveDone flag so there can be started a new move.
The game itself is gridbased so if a move is done the squence starts a move to the next grid depending on the direction. So here is how it looks like:
note that this is inside of the Act of the figure
....//some more here
if (checkNextMove(Status.LEFT)) //check if the position is valid
{
status = Status.LEFT; //change enum status
move(Status.LEFT); // calls the move
screen.map.mapArray[(int) mapPos.x][(int) mapPos.y] = Config.EMPTYPOSITION;
screen.map.mapArray[(int) (mapPos.x - 1)][(int) mapPos.y] = Config.CHARSTATE;
mapPos.x--;
moveDone = false;
}
//... same for the up down right and so on.
//at the end of this checking the updating of the actor:
// methode from the absctract to change sprites
updateSprite(delta);
super.act(delta); // so the actions work
//end of act
And here is the move Method that does add the Actions
protected void move(Status direction)
{
// delete all old actions if there are some left.
clearActions();
moveAction.setDuration(speed);
//restart all actions to they can used again
sequence.restart();
switch (direction)
{
case LEFT:
moveAction.setPosition(getX() - Config.TILE_SIZE, getY());
addAction(sequence);
break;
case RIGHT:
moveAction.setPosition(getX() + Config.TILE_SIZE, getY());
addAction(sequence);
break;
case UP:
moveAction.setPosition(getX(), getY() + Config.TILE_SIZE);
addAction(sequence);
break;
case DOWN:
moveAction.setPosition(getX(), getY() - Config.TILE_SIZE);
addAction(sequence);
break;
default:
break;
}
}
The figures dont really move smothy.
Anyone does see a misstake or isnt it possible to let them move smothy like this?
It always stutter a bit if a new move is started. So i think this might not work good. Is there a differnt approach to move them exactly from one Grid to an nother? (Tried it myself with movementspeed * delta time but this does not work exactly and i struggeled around and used the Actionmodel)
it seems to make troubles with the one Frame where it does not move for example.
Here is an mp4 Video of the stuttering:
stuttering.mp4
just to mention, the camera movement is just fine. it's smothy but the figure stutters as you can see i hope
If you use your moveAction each move, you should call moveAction.restart() to reset the counter inside it:
// delete all old actions if there are some left.
clearActions();
sequence.reset(); // clear sequence
// add movementspeed. Note it can change!
moveAction.restart();
moveAction.setDuration(speed);
UPDATE:
Now issue occurs, because you call restart of SequenceAction after clearActions(). If your clearActions() removes all actions from SequenceAction then restart will be called for empty SequenceAction. So, do this instead:
//restart all actions to they can used again
sequence.restart();
// delete all old actions if there are some left.
clearActions();
moveAction.setDuration(speed);
Okay so i solved it myself. It has nothing todo with changing sequences around. It has something todo with the updatefrequency of the act() of the figures. The MoveToAction interpolates between the 2 points given by time. So if the last update, updates the MoveToAction by "to much time" it would need to go over the 100% of the action. So it would move to far but the action does not do this it set the final position and thats what it should do. Thats why it does not look fluent.
So how to solve this issue?
By decreasing the updatetime the "to far movement" decreases too because the steplength is getting smaller. So i need to increase the updatespeed above the 60fps. Luckily i got an thread for my updating of the figures and positions and so on. GameLogicThread. This ran on 60fps too. So i solved the stuttering by increasing it's frequence. up to around 210fps at the moment so the "overstep" is minimal. You can't even notice it.
To Show how my thread works:
public class GameLogicThread extends Thread
{
private GameScreen m_screen;
private boolean m_runing;
private long m_timeBegin;
private long m_timeDiff;
private long m_sleepTime;
private final static float FRAMERATE = 210f;
public GameLogicThread(GameScreen screen)
{
m_screen = screen;
setName("GameLogic");
}
#Override
public void run()
{
m_runing = true;
Logger.log("Started");
while (m_runing)
{
m_timeBegin = TimeUtils.millis();
// hanlde events
m_screen.m_main.handler.processEvents();
synchronized (m_screen.figureStage)
{
// now figures
if (m_screen.m_status == GameStatus.GAME)
{
m_screen.character.myAct(1f / GameLogicThread.FRAMERATE);// and here it is ;)
m_screen.figureStage.act(1f / GameLogicThread.FRAMERATE);
}
}
m_timeDiff = TimeUtils.millis() - m_timeBegin;
m_sleepTime = (long) (1f / GameLogicThread.FRAMERATE * 1000f - m_timeDiff);
if (m_sleepTime > 0)
{
try
{
Thread.sleep(m_sleepTime);
}
catch (InterruptedException e)
{
Logger.error("Couldn't sleep " + e.getStackTrace());
}
}
else
{
Logger.error("we are to slow! " + m_sleepTime);
}
}
}
public void stopThread()
{
m_runing = false;
boolean retry = true;
while (retry)
{
try
{
this.join();
retry = false;
}
catch (Exception e)
{
Logger.error(e.getMessage());
}
}
}
}

Guess the next position of simultaneously running threads

I am making a maze and two threads are moving on it simultaneously.The problem they mustn't share the same position at same time. I don't know how I can do it. Is it possible to know where they will move next and prevent the other thread from moving to that position? Please give me an idea. Thanks.
Here the code :
public int[][] visitedCell=new int[15][15]; // holds how many times visited for each cell
public boolean cntrl=true,repeat=true,end;
public int r=0;
public int cnt;
public boolean find;
public void decision(int posX,int posY){
int distanceToExit;
cnt=0; // holds how many cell is free around the cell which thread is on
r=0;
end=false; // checks robot found exit
find=false; // checks suitable cell found to move in next step
posX=posX/40; // all cells are 40*40 dimension.since it is divided 40 to find poisition
posY=posY/40; // found y position
int[][] neighbours={{posX,posY+1},{posX+1,posY+1},{posX+1,posY},{posX+1,posY-1},{posX,posY-1},{posX-1,posY-1},{posX-1,posY},{posX-1,posY+1}}; // all 8 neighbours of a cell
int[][] freeCellChoises = new int[8][2]; // holds free cells to move
int[][] distanceCell=new int[8][2];
for(int i=0;i<8;i++){ // checks which neighbour cells are free
if((neighbours[i][0] >0 && neighbours[i][0] <14) && (neighbours[i][1] >0 && neighbours[i][1] < 14) || (neighbours[i][0]==1 && neighbours[i][1]==14) || (neighbours[i][0]==14 && neighbours[i][1]==1) ) // [1,14] = enter position and [14,1]= exit position
{
if(Draw.paintArray[neighbours[i][0]][neighbours[i][1]]==0){// cell is free.it is eligible
freeCellChoises[cnt][0]=neighbours[i][0]; // load eligible cells this array
freeCellChoises[cnt][1]=neighbours[i][1];
distanceToExit=(int) Math.sqrt((Math.pow(neighbours[i][0]-560, 2)+Math.pow(neighbours[i][1]-40,2)));
distanceCell[cnt][0]=cnt;
distanceCell[cnt][1]=distanceToExit;
cnt++;}
}
} // eligible cells are ready anymore
if(Frame.radButSel==1){ // random movement
int no=rndm.nextInt(cnt); // choose one of the eligible cell randomly
x=freeCellChoises[no][0] * 40;
y=freeCellChoises[no][1] * 40;
}
if(Frame.radButSel==2){ // closed way movement ( find the most clodes cell to the exit ) .Exit is [14,1].So x must be max, y must be min to a cell has priority
int maxX=freeCellChoises[0][0];
int minY=freeCellChoises[0][1];
int selection1=0,selection2=0;
for(int i=0;i<cnt;i++){ // x i byk y si kck sec
if(freeCellChoises[i][0]> maxX){
maxX=freeCellChoises[i][0];
selection1=i;}
if(freeCellChoises[i][1]<minY){
minY=freeCellChoises[i][1];
selection2=i;
}
}
if(cnt!=0) // checks there is a priority cell
r=rndm.nextInt(2)+1; // selects one of the priority cell
if(r==1 && visitedCell[freeCellChoises[selection1][0]][freeCellChoises[selection1][1]] <2){ //selection1.same cell musnt be visited more than 2 times
x=freeCellChoises[selection1][0] * 40;
y=freeCellChoises[selection1][1] * 40;}
else if(r==2 && visitedCell[freeCellChoises[selection2][0]][freeCellChoises[selection2][1]] <2){//selection2
x=freeCellChoises[selection2][0] * 40;
y=freeCellChoises[selection2][1] * 40;}
else{ // applies when there is not any priority cell
System.out.println("oncelik yok");
int repeat =0;
while(repeat<cnt){
r=rndm.nextInt(cnt); // choose one of the eligible cell
x=freeCellChoises[r][0] * 40;
y=freeCellChoises[r][1] * 40;
if(visitedCell[freeCellChoises[r][0]][freeCellChoises[r][1]] <2){
repeat=10;
}
else
repeat++;
}System.out.println("x="+x+"y="+y);
}
}
if(Frame.radButSel==3){
}
if(x==560 && y==40){ // checks decided cell is exit point
Action.pool.shutdownNow();// thread finished
end=true;
Main.butAct++; // when butAct=2 , "RESULT" button will be active
timer.stopTime();} // stops time for the thread
distance=(int) Math.sqrt(Math.pow(x-560,2) + Math.pow(y-40, 2));// calculates distance between thread - exit
}
public Action() throws InterruptedException{
pool=Executors.newFixedThreadPool(2); // two thread in the pool
robot1=new Robot(40,560); // starts enter position
robot2=new Robot(40,560); // starts enter position
pool.submit(robot1); // loads robot1 to pool
pool.submit(robot2);// loadss robot2 to pool
}
public void run() {
while(true){ // run threads always
try {
Frame.worker.pauseIfNeeded();} // checks whether pause button is pressed
catch (InterruptedException ex) {
Logger.getLogger(Robot.class.getName()).log(Level.SEVERE, null, ex);}
if(end==false){// not reach exit
try{
System.out.println(Thread.currentThread().getName());// displays current thread name
System.out.println("pozisyon x="+x+"y="+y);
decision(x,y); // thread makes decision to move
visitedCell[x/40][y/40]+=1; // increade number of visitide cell count for that cell in the array
visCell++; //increase visited cell count for the thread
Thread.sleep(300);} // thread sleeps for a while to observe movement changing
catch(Exception ex){
}
}
else{// found exit
Thread.currentThread().interrupt(); // Thread killed
if(Main.butAct==2)// after a thread found exit, checks if result button can be active anymore
Frame.button4.setEnabled(true); // activates result button
}
}//end while
}
Or you could do it something like this. The manager class is aware of the position of both threads, and the moveTo method checks that they don't coincide at the same location.
class MazeManager {
int x1, x2, y1, y2;
public synchronized boolean moveTo(int threadId, int x, int y) {
..
}
}
The most simple solution would be to "divide" the work in such a way that the two work regions (solutions/paths to be tried out) are mutually exclusive. A workaround would be to have a concurrent set of positions which would be checked by each thread before making a move.
You will have to use the concept of so called mutual exclusion. In the Java programming language, you will have to use the synchronized keyword to do the job for you. A simple example maybe seen at [1]:
public class SynchronizedCounter {
private int i = 0;
public synchronized void increment() {
i++;
}
public synchronized void decrement() {
i--;
}
public synchronized int value() {
return i;
}
}
Here you see a code that makes sure that only one thread is able to modify the value of the shared variable i. Note that the code uses this as the so-called "lock object". You may rewrite the code in the following way:
public class SynchronizedCounter {
private int i = 0;
public void increment() {
synchronized(this) {
i++;
}
}
public void decrement() {
synchronized(this) {
i--;
}
}
public int value() {
synchronized(this) {
return i;
}
}
}
Or you may want to create your own lock object and use it:
public class SynchronizedCounter {
private int i = 0;
private Object lock = new Object();
public void increment() {
synchronized(lock) {
i++;
}
}
public void decrement() {
synchronized(lock) {
i--;
}
}
public int value() {
synchronized(lock) {
return i;
}
}
}
Now any number of threads may call the methods of this object randomly, but only one thread at one time will be able to pass the lock and do the actual modification.
[1] http://docs.oracle.com/javase/tutorial/essential/concurrency/syncmeth.html
Have the class that manages the maze force the threads to synchronize through itself, and make requests to change their position. The maze manager can then allow or deny requests to move based on the position of other threads.
Like Sanjay says, prevention is better than cure. You can partition the cells traversed by the two robots such that they never share the same cell.
If that is not possible, the cure is to use locks for each of the cells. Robots obtain the corresponding lock before moving into the cell and release the lock when done. This will cause a robot to wait if it is trying to enter the same cell as another robot. This is a more decentralized approach than having the maze manager control the moves and will result in less contention.

Categories

Resources