So I the app lets a user place down blocks on a grid, if the user lines up 3 or more blocks with the same suit, or color, then something happens. When player places a block I call this method:
blocks_.add(new Block(new Vector2(rect_mouse.x, rect_mouse.y), blocks_.get(0).blockID, blockCount));
When you place 3 or more together I call these methods:
blocks_.removeValue(blocks_.get(left_bravo_indexNum), true);
blocks_.removeValue(blocks_.get(center_charlie_indexNum), true);
blocks_.removeValue(blocks_.get(right_alpha_indexNum), true);
stack:
Exception in thread "LWJGL Application" java.lang.IndexOutOfBoundsException: 13
at com.badlogic.gdx.utils.Array.get(Array.java:125)
at com.jrp.mygearapp.GameScreen.touchUp(GameScreen.java:1443)
at com.badlogic.gdx.backends.lwjgl.LwjglInput.processEvents(LwjglInput.java:297)
at com.badlogic.gdx.backends.lwjgl.LwjglApplication.mainLoop(LwjglApplication.java:186)
at com.badlogic.gdx.backends.lwjgl.LwjglApplication$1.run(LwjglApplication.java:110)
This was intended to remove the blocks, but it resulted in this IndexOutOfBoundsException. Is there a way to prevent this error?
This could be occurring because the array auto sorts the number of elements and lowers the number to the correct number of elements in the array, and I still have elements that are labeled higher then the size of the array. I am still a novice, so my analysis could be incorrect. Please alert me if this is the case and help me find a fix.
Thanks.
edirted* TouchUp() function-------
#Override
public boolean touchUp(int x, int y, int pointer, int button) {
if (button == 0) {
display_blockCheck = false;
////set blockCount to the size of blockArray so blocks can properly be indexed
blockCount = blocks_.size;
if (!overlap) {
Gdx.app.log("Block Added", "x: " + x + " y: " + y);
updateQueueBlocks();
//add block
Vector2 rect_vector = new Vector2(rect_mouse.x, rect_mouse.y);
Block block = new Block(rect_vector,blocks_.get(0).blockID, blocks_.size);
blocks_.add(block);
if (center_charlie_suit == "Square") {
center_charlie_bool = true;
if (right_bravo_suit == "Square") {
right_bravo_bool = true;
if (right_alpha_suit == "Square") {
Gdx.app.log("3-pair", "Square:345:lr");
right_alpha_bool = true;
//call 3-pair event
blocks_.removeValue(blocks_.get(center_charlie_indexNum), true);
blocks_.removeValue(blocks_.get(right_alpha_indexNum), true);
blocks_.removeValue(blocks_.get(right_bravo_indexNum), true);
}
}
}
the rest is just really long and just checks for other blocks next to each other..
You're right, as you remove the blocks, the indexes change.
You don't show what type of Collection blocks_ is (Vector2?, did you write it?), however, rather than tracking the indices of the elements, simply track the elements themselves and call remove() to find and remove that element.
Related
I'm developing an application in Java to help me land my first job as a junior developer. It's a chess game with a GUI that both human players click on from the same machine.
When it's, say, white's turn to move, the application calls white's getMove(Interface interaction) method until a valid MoveAttempt is returned. Here's the getMove(Interface interaction) method of HumanPlayer:
public MoveAttempt getMove(Interface interaction) {
while(!interaction.selectionMade()) {
}
byte pieceFile = interaction.getPenultimateFile();
byte pieceRank = interaction.getPenultimateRank();
byte toFile = interaction.getUltimateFile();
byte toRank = interaction.getUltimateRank();
return new MoveAttempt(pieceFile, pieceRank, toFile, toRank, getIsWhite());
}
penultimateFile, penultimateRank, ultimateFile and ultimateRank are supposed to store the file (column) and rank (row) of the last two chess tiles clicked. This is achieved through this actionPerformed(ActionEvent event) which Interface has because it implements ActionListener
public void actionPerformed(ActionEvent event) {
LocalizedButton button = (LocalizedButton) event.getSource();
if(penultimateFile == -1) {
penultimateFile = button.getFile();
penultimateRank = button.getRank();
}
else {
ultimateFile = button.getFile();
ultimateRank = button.getRank();
}
}
and by calling this method before each call to getMove(Interface interaction)
public void resetClicks() {
penultimateFile = -1;
penultimateRank = -1;
ultimateFile = -1;
ultimateRank = -1;
}
So the idea is that a move attempt is not made until someone has clicked on two chess squares which is why I have a while loop indefinitely calling selectionMade():
public boolean selectionMade() {
return penultimateFile != -1 && penultimateRank != -1 && ultimateFile != -1 && ultimateRank != -1;
}
This didn't work---pieces didn't move---so in an attempt to see what was happening I put this print statement
System.out.println(interaction.getPenultimateFile() + ", " +
interaction.getPenultimateRank() + ", " +
interaction.getUltimateFile() + ", " +
interaction.getUltimateRank());
into the while loop to see what was going on and now it works---pieces move---except I may have encountered times in which it didn't work but I last I tried I couldn't get it to fail.
I don't want to print anything to the console; what should I do in lieu of having this while loop?
Edit: Putting boolean lol = 0 just above the loop and lol = !lol in the loop doesn't allow the code to work. Neither does calling doNothing().
Edit: Here's the source code: https://github.com/JosephBGriffith/Chess
Right now only the pawns work because I have other bugs that I need to fix. En passant works except the opponent piece doesn't get eliminated.
I would invert the control, so that the UI pushes moves to the game, rather than the game trying to pull moves from the UI.
So your game class might have:
class Game {
boolean move(int fromFile, int fromRank, int toFile, int toRank) { ... }
...
}
If the move wasn't legal (e.g. if it was the other player's turn) then move returns false and the move doesn't occur. That is, the internal state of the Game is unchanged.
And your actionPerformed method becomes:
public void actionPerformed(ActionEvent event) {
LocalizedButton button = (LocalizedButton) event.getSource();
if(penultimateFile == -1) {
penultimateFile = button.getFile();
penultimateRank = button.getRank();
}
else {
game.move(penultimateFile, penultimateRank, button.getFile(), button.getRank());
penultimateFile = -1;
}
}
You could use the return value of move to provide some feedback to the user if the move is illegal.
Something to note about this suggestion is that move is executed on the Swing event thread. In theory this is bad practice, although unless your move method is very slow it won't matter.
Read https://docs.oracle.com/javase/tutorial/uiswing/concurrency/index.html and consider whether you want to use invokeLater.
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.
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).
Could anyone tell me why this is returning the error
'AL lib: (EE) alc_cleanup: 1 device not closed'
//mouseJoint collision callback
private QueryCallback queryCallback = new QueryCallback() {
#Override
public boolean reportFixture(Fixture fixture) {
if(fixture.getBody() == chest){
//add to remove list
bodiesToRemove.add(chest);
}
if (fixture.testPoint(tmp.x, tmp.y)){
reportFixture = fixture.getBody();
}
if (!fixture.testPoint(tmp.x, tmp.y))
return false;
//assigning bodyB to fixture
jointDef.bodyB = fixture.getBody();
jointDef.target.set(fixture.getBody().getWorldCenter());
//jointDef.target.set(tmp.x, tmp.y);// initial target point coincide with body anchor
joint = (MouseJoint) world.createJoint(jointDef);// creating the join the physics world
return false;
}
};
//main rendering loop
public void render(float delta) {
// TODO Auto-generated method stub
//code clears the screen with the given RGB colour (black)
Gdx.gl.glClearColor( 0f, 0f, 0f, 1f );
Gdx.gl.glClear( GL20.GL_COLOR_BUFFER_BIT );
stage.setCamera(camera);
stage.act(Gdx.graphics.getDeltaTime());
camera.position.x= chest.getPosition().x;
camera.update();
stage.draw();
world.step(1 / 60f, 8, 3);
renderer.render(world, camera.combined);
/////////////////////////////////////////////////////////////////
// this is the code that is causing the error when I try to delete a body
if(bodiesToRemove != null){
for(int i = 0; i <bodiesToRemove.size; i++){
Body b = bodiesToRemove.get(i);
if(b != null){
world.destroyBody(b);
b.setUserData(null);
b = null;
}
bodiesToRemove.clear();
}
}
////////////////////////////////////////////////////////////
}
////////////////////////////////////////////////////////////////////////////
I've changed this and it work's(pasted below), if anyone would like to explain the right way to do this or if this is the correct way that would be helpful.
I just added a boolean to prevent it from destroying the joint
// ////////////////// TOUCH EVENT ///////////////////////////////
//Called when a finger was lifted or a mouse button was released.
#Override
public boolean touchUp(int screenX, int screenY, int pointer, int button) {
//If no mouseJoint do nothing
System.out.println("touch" + (screenY*0.01f));
System.out.println("touch" + (screenX*0.01f));
if (joint == null)
return false;
//When user is not touching Screen destroy the
//mouseJoint/set to null
if(ran == false){
world.destroyJoint(joint);
joint = null;}
ran = false;
return true;
}
////////////////////////////////
/////////////////////////////////
if(!world.isLocked() && world.getBodyCount() > 0 ){
for(int i = 0; i <bodiesToRemove.size; i++){
Body b = bodiesToRemove.get(i);
if(b == null){
bodiesToRemove.removeIndex(i);
continue;
}
world.destroyBody(b);
ran = true;
bodiesToRemove.removeIndex(i);
}
}else{
bodiesToRemove.clear();
}
////////////////////////////////////////////////////////////
Box2D throws some odd errors, this is not one of them.
I assume you are using LibGDX, basically what is happening is a crash due to Box2D (I also assume it pops up saying "java or whatever has stopped responding"), this error you are seeing is thrown when the app exits while OpenAL is closing streams and cleaning up resources. Don't worry about that too much.
Ensure you are checking of the world is locked before destroying bodies, it usually throws an error and prints a clear message telling you this, depending on the way you are removing bodies.
if(!world.isLocked())
// do clean up code here
You don't need to clean up the variable inside local scope, or clear the userdata inside the body as the body as it will no longer exist in reference (unless you have it stored somewhere else).
So the proper code would be something like this:
if(!world.isLocked()){
for(int i = bodiesToRemove.size - 1; i--){
Body b = bodiesToRemove.get(i);
if(b == null){
bodiesToRemove.removeAt(i);
continue;
}
world.destroyBody(b);
bodiesToRemove.removeAt(i);
}
}
You are also clearing a list during iteration, not a good idea.
EDIT
The only other thing I can think of that is causing this problem is trying to delete a body that is not actually in the worlds body list.
Try the following:
// Ensure world is not locked AND that there is even bodies in the world
if(!world.isLocked() && world.getBodyCount() > 0){
for(int i = bodiesToRemove.size - 1; i--){
Body b = bodiesToRemove.get(i);
if(b == null){
bodiesToRemove.removeAt(i);
continue;
}
world.destroyBody(b);
bodiesToRemove.removeAt(i);
}
}else{
// There is no bodies in the world, so the bodies in our list are just
// random memory hogs, leave them for the GC by clearing the list
bodiesToRemove.clear();
}
EDIT
As stated by the OP, the problem lies with this block of code:
private QueryCallback queryCallback = new QueryCallback() {
#Override
public boolean reportFixture(Fixture fixture) {
if(fixture.getBody() == chest){
//add to remove list
bodiesToRemove.add(chest);
}
if (fixture.testPoint(tmp.x, tmp.y)){
reportFixture = fixture.getBody();
}
if (!fixture.testPoint(tmp.x, tmp.y))
return false;
//assigning bodyB to fixture
jointDef.bodyB = fixture.getBody();
jointDef.target.set(fixture.getBody().getWorldCenter());
//jointDef.target.set(tmp.x, tmp.y);
joint = (MouseJoint) world.createJoint(jointDef);
return false;
}
};
More specifically, this line:
joint = (MouseJoint) world.createJoint(jointDef);
The query callback is triggered during a world step. In Box2D, you can not create or destroy bodies, fixtures, and joints during the world step.
You have to create it outside this method, the simplest way to do it is via a flag. Set a flag to true and store the instance of the fixture somewhere and handle it outside in the game loop using said flag and fixture.
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.