Breadth-First-Search for moving dot game - java

Hi I having been trying to program an algorithm using breadth-first-search that finds the shortest path for the blue dot to exit in the game. I am new to java and having trouble running/understanding the algorithm for the class. I have a class called gameModel which stores the statuses of each dot. The algoirthm is meant to test the fastest way the blue dot can exit the board without going through an orange dot (SELECTED) and if no way out than the player wins. I keep running the program and getting compile errors which i dont know how to fix. I included the controller class where the short dot was ran.
import java.util.Random;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.*;
/**
* The class <b>GameController</b> is the controller of the game. It implements
* the interface ActionListener to be called back when the player makes a move. It computes
* the next step of the game, and then updates model and view.
*/
public class GameController implements ActionListener {
private int size;
private GameModel gameModel;
private GameView gameView;
private boolean click;
/**
* Constructor used for initializing the controller. It creates the game's view
* and the game's model instances
*
* #param size
* the size of the board on which the game will be played
*/
public GameController(int size) {
this.size = size;
this.gameModel = new GameModel(size);
this.gameView = new GameView (gameModel, this);
click = false;
}
/**
* Starts the game
*/
public void start(){
if (click){
List start = new List {gameModel.getCurrentDot().getX(), gameModel.getCurrentDot().getY()};
List<int> targets = new ArrayList<>();
List<int> blocked = nwq ArrayList<>();
for (int i = 0; i < size; i++){
targets.add(i, 0);
targets.add(i, size);
targets.add(1, size);
targets.add(1, 0);
}
for (int i = 0; i < size; i++){
for (int j = 0; j < size; j++)
if(gameModel.getstatus(i, j) == SELECTED){
blocked.add(i, j);
}
String path = Breadth-First-Start(start, targets, blocked);
gameView = new GameView(gameModel, this);
gameView.getBoardView().update();
}
}
public Breadth-First-Start(start, targets, blocked){ // Need help with
Queue queue = new LinkedList();
queue.add(start + "");
while(!queue.isEmpty()){
String p = queue.remove();
if (p != blocked){ //If p is not in blocked paths
if (p == targets){ //If p is in targets
return "q + {p}";
} else {
queue.add("q + {p}");
blocked.add(p);
}
}
}

You method public Breadth-First-Start(start, targets, blocked) is declared wrong. You cant have - in method name, also you need to specify the return type (only constructors dont have a return type to be defined). Also you need to specify parameter types. From what I understand targets and start look like of type String and blocked looks like a List, please try replace the method head by the following public void breadthFirstSearch(String start, String targets, List blocked) not sure what return type you want as you dont have any returns in the method. But in your case you probably want the path so maybe of type List, or a boolean to know if there is a path or not.

What you're wanting to do has to do with graph theory. If two nodes are connected, an edge between them is created. In this case the orange dots would not be connected to anything as a path cannot exist through them. Dijkstra's algorithm is very useful for doing what you want, although it's breadth first instead of depth first. I'd recommend starting there, I'm sure there are examples of that algorithm being implemented in java.
The edges of the graph have weights which are compared in order to find the shortest path between two nodes.
I see that your blocked list declaration has nwq in it instead of new. That may be your issue right there.
Hope this helps

Related

OOP desing, Java Swing, chess game, instanceof

OK, I'm in the process of making a simple java swing chess game. This question is more about OOP design then Java Swing.
I have the following:
I have a Panel class that implements JPanel.
I then have an abstract class Piece that extends from my Panel class
Then I have my classes for the different Pieces: Pawn, King, Bishop etc that extend from my Pieces class
In my main ChessGame Class:
I am using an array of Panel to store the layout of my board
So the array will store, Panel objects, for board places with no pieces on it.
And it will store, the subclasses such as Pawn, Queen, Bishop etc (board places with pieces)
So, the top left square (0,0) maps to myArray[0][0]
My problem is that, to check if the place is empty or has chess pieces in it I have to use:
if(panels[x][y] instanceof Piece){
((Piece)panels[x][y]).makeMove();
}
What I'm asking is this terrible design? I know I should try and stay away from instanceof.
What would be a better approach?
Thanks.
You shouldn't combine the Model code (Piece) with the view code (JPanels). If you ever want to change how the board is displayed you have to change how pieces are stored!
A better design might be to separate Piece from JPanels. Then you can use a single JPanel to display a matrix of Pieces : Pieces[8][8].
My problem is that, to check if the place is empty or has chess pieces in it I have to use:
If you use a matrix, you can just have a null cell or use the Null Object Pattern to have an "empty" piece.
EDIT
Each cell in the piece matrix is a square in the board so piece[0][0] would be the top corner of the board (A8).
To paint the board your paintComponent() method would have to iterate over this matrix and draw each cell appropriately. There are several ways to implement this:
You would need to do a similar instanceof check to draw each type of piece differently
Make a new intermediate "paint strategy" object using the strategy pattern. This may require a matrix of strategy objects instead of piece objects. You may still need to do instance of checks, but maybe only the once to create the strategy objects.
After considering your problem, and knowing the problem domain, I would actually suggest the following...
In your class Panel implement a function int hasMass() as follows...
public int hasMass() {
return 0;
}
In your class Piece override that function as follows...
public int hasMass() {
if (isWhite()) // white pieces are negative.
return -1;
return 1; // black pieces positive.
}
Now you can check if the square has a piece, whether another given piece could take it... (because they have opposite polarity)... e.g. mass + mass == 0 means a capture, != 0 means the panel was empty. And of course an absolute value of 2 (for mass) would mean the move was illegal.
OK, ill start by throwing away the option of setting null to indicate that place is empty (you can do it ofc but using the Empty class is just 'better' in a way).
So let's say you have array of Panels representing your game board:
Panel[][] board;
Now for ilustration, how your class hierarchy could look like:
abstract class Panel extends JPanel { ... }
class Empty extends Panel { ... }
abstract class Piece extends Panel { ... }
class Pawn extends Piece { ... }
...
My Panel class is my Empty class is it not?
Not sure if i understand you, but let's have a look on what extends means exactly: in the show nmodel every Piece is also a Panel or every Pawn is also a Piece, so every Pawn can do all the same things as Piece (for example, 4 is complex number as well as natural number or real number, so in a way, you could say that real numbers extend complex numbers, since every real number is also a complex number)
So now you can have some nice abstract getTexture() method declared in Panel implemenented in Empty class and in all Piece subclasses, and when drawing a Panel, you dont need to look if it is empty or not.
Instead of creating (I assume) almost identical classes for each piece (Rook, Pawn, Queen etc.), you could just keep the original Piece class, make it non abstract and add a PieceType field to it. PieceType is just an enum that tells what type of piece (if any) is placed there. Instead of using instanceof, now you can check using panels[i][j].getType() == PieceType.ROOK. At least that's what I'm doing in my implementation :)
I'm also using JLabel instead of JPanel for my 8x8 board.
Instead of splitting panel to 8x8 smaller panels, you must draw the board and the pieces on a canvas. Later the players will eventually be dragging to move pieces on board. Also you could look for Bitboard presentation in chess game, although this presentation is only required for chess engines which are able to "think" for fast calculations, it is still useful when you have to check if the move that player is trying to make is correct.
Posible Bitboard:
public class BitBoard
{
public static final int P = 0;
public static final int N = 2;
public static final int B = 4;
public static final int R = 6;
public static final int Q = 8;
public static final int K = 10;
public static final int p = 1;
public static final int n = 3;
public static final int b = 5;
public static final int r = 7;
public static final int q = 9;
public static final int k = 11;
// empty field
public static final int empty = 12;
// number of pieces , squares
public static final int nPieces = 12;
public static final int nSquares = 64;
public static final int whitePieces = 12;
public static final int blackPieces = 13;
public static final int nBoards = 14;
public static long squareBits[];
// static member initialization
static
{
squareBits = new long[64];
long square = 1;
square = square << 8 * 8 - 1;
for (int i = 0; i < 64; i++) {
squareBits[i] = square >>> i;
}
}
long bitBoards[];
public BitBoard() {
bitBoards = new long[nBoards];
}
public boolean initBoard()
{
// Put the pieces on the board
EmptyBoard();
addPiece(0, r);
addPiece(1, n);
addPiece(2, b);
addPiece(3, q);
addPiece(4, k);
addPiece(5, b);
addPiece(6, n);
addPiece(7, r);
for (int i = 8; i < 16; i++) {
addPiece(i, p);
}
for (int i = 48; i < 56; i++) {
addPiece(i, P);
}
addPiece(56, R);
addPiece(57, N);
addPiece(58, B);
addPiece(59, Q);
addPiece(60, K);
addPiece(61, B);
addPiece(62, N);
addPiece(63, R);
return true;
}
public boolean addPiece(int whichSquare, int whichPiece)
{
bitBoards[whichPiece] |= squareBits[whichSquare];
bitBoards[nPieces + (whichPiece % 2)] |= squareBits[whichSquare];
return true;
}
private boolean removePiece(int whichSquare, int whichPiece)
{
bitBoards[whichPiece] ^= squareBits[whichSquare];
bitBoards[nPieces + (whichPiece % 2)] ^= squareBits[whichSquare];
return true;
}
private boolean EmptyBoard()
{
for (int i = 0; i < nBoards; i++)
{
bitBoards[i] = 0;
}
return true;
}
}
I would keep a structure of the pieces separate from the rendered board.
For example, I would make the chess pieces pure models w/o knowledge of hit they're rendered.
Pieces (baseclass)
+- Pawn
+- Knight
+- King
+- Queen
+- ..etc
This will allow you to keep an array of Pieces only, where empty squares are null.
For simplicity sake, I'd just have a matrix of peices:
Peices[][] board = new Pieces[8][8];
(of course an initialization method to traverse your 'board' and populate the board w/ the initial positions)
I would then have a visible board constructed of JPanels; a class called "Chess" to manage game; and the actual rendering of the tile/panel in the move function. Imagine:
// what a move might look like when initializing your panels
piece = board [0][0];
Chess.move(piece, 0 ,0); //responsible for clearing the old panel and rendering the panel at target location.
When the user interacts w/ your game..they click your panels..which will give you the panel coordinates. You use the same coordinates w/ your 'board' to determine what the piece is..how it can move etc..
Something like that...
I would just represent the game board using objects...for simplicity. Easiest to understand..and besides..computers are plenty fast now.

creating new array when adding/deleting elements?

Good Evening. I am working on a program thats similar to the old game LiteBrite, where you place colored pegs on a panel and it lights up. In my program, it works similar in that when you click on the panel, it will create a new Ellipse (which ive named ColorEllipse that has specifications for location, size, and color) and that it will store it to be saved. Currently it is as an arraylist but i need it to be in a regular array. I am told the way that would be to make a new array, and copy all the contents of the old array into the new array. Now currently i use an arraylist, but unforutnately this program has specifications where we need to use a regular Array.
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.lang.reflect.Array;
import java.util.ArrayList;
public class LiteBritePanel extends javax.swing.JPanel{
private final static int OFFSET = 5;
private static int LINE_WIDTH = 2;
private static int CELL_WIDTH = 25;
public ArrayList <Colorable> _circles; // where ColorEllipses will be stored
private ButtonPanel controlpanel; // used to set the color of peg that will be placed
public LiteBritePanel() {
this.setBackground(java.awt.Color.black);
_circles = new ArrayList<Colorable>();
controlpanel = new ButtonPanel(this);
this.addMouseListener(new MyMouseListener(this));
this.add(controlpanel);
}
public void paintComponent(java.awt.Graphics aPaintBrush) {
super.paintComponent(aPaintBrush);
java.awt.Graphics2D pen = (java.awt.Graphics2D) aPaintBrush;
java.awt.Color savedColor = pen.getColor();
pen.setColor(java.awt.Color.black);
for (int ball=0;ball<_circles.size();ball++)
if(_circles.get(ball).isEmpty())
return;
else
_circles.get(ball).fill(pen);
pen.setColor(savedColor);
this.repaint();
}
public void mouseClicked(java.awt.event.MouseEvent e){
boolean foundSquare = false;
for (int ball=0; ball < _circles.size() && !foundSquare; ball++){
if (_circles.get(ball).contains(e.getPoint()) == true){
foundSquare = true;
_circles.remove(ball);
this.repaint();
}
}
}
private class MyMouseListener extends java.awt.event.MouseAdapter {
private LiteBritePanel _this;
public MyMouseListener(LiteBritePanel apanel){
_this = apanel;
}
public void mouseClicked(java.awt.event.MouseEvent e){
_circles.add(new ColorEllipse(controlpanel.getColor(), e.getPoint().x - (e.getPoint().x%CELL_WIDTH), e.getPoint().y - (e.getPoint().y%CELL_WIDTH), CELL_WIDTH-3,_this));
_this.requestFocus();
boolean foundSquare = false;
for (int ball=0; ball < _circles.size() && !foundSquare; ball++){
if (_circles.get(ball).contains(e.getPoint()) == true){
foundSquare = true;
// code for removing ball if one is placed
_this.repaint();
}
}
}
}
}`
Now currently it is set as an Arraylist, but I need it to be in a regular array per this specification. then when the panel is clicked on, it adds a new ColorEllipse into that Array at that specific location (and repaints as necessary for it to show up). A later part of the program would be when i touch a peg thats already placed, it removes it, but thats for another time. right now I need to know how to increment sizes of the array and copy its contents into it. Would anyone be able to tell me what I should change?
To copy arrays, you could use the System.arraycopy(...) method (System API):
public static void arraycopy(
Object src,
int srcPos,
Object dest,
int destPos,
int length)
where you would first create a destination array, perhaps twice as big as the the source array, and pass the old array, the starting index (0), the new array, the destination starting index (0), the length (length of old array), and it should do the rest.
Also you don't want to call repaint inside of paintComponent, trust me. Use a Swing Timer instead. There's a good tutorial on this that Google can help you find.
Depending on how big your board is you can just create an array that has the same size as your board. Alternatively you can do as Hovercraft suggested but it all depends on whether you want to trade cpu for memory.
int MAX_POSSIBLE_ELEMENTS = ...
Colorable[] _circles = new Colorable[MAX_POSSIBLE_ELEMENTS];
....rest of code...
Notice that the maximum number depends on the height and width of the board so you should know this at compiletime.

Java TicTacToe Game

I'm working on my assignment which is to create a TicTacToe checker, and for some reason I'm unable to think of a way to do the first steps of creating the game. We read in from a text file that contains a line which represents one game; for example:
x,x,o, , ,x, ,o,o
That would look like this on a traditional board:
x|x|o
-----
| |x
-----
|o|o
Here's what I have so far:
class TicTacToe{
static String[][] game;
public TicTacToe(int size){
this.game = new String[size][size];
}
public static TicTacToe create(String input){
String tokens = input.split(",");
int size = (int)Math.sqrt(tokens.length); //For setting a size
// of the board
return null;
}
}
What I don't understand is how to return a new TicTacToe object: when I write my methods for checking rows, columns, etc. how will I get the board to check on? Am I going about this the right way?
[W]hen I write my methods for checking rows, columns, etc. how will I
get the board to check on?
The instance of your object should contain all of the information about the board. You have this (mostly) done already - game is the field which contains the information about the board. The only catch is that every board will contain the same board information, and if it's updated, it will contain the updated information.
If you want to treat this like a factory, then there are four things that you'll want to do:
Remove the static modifier from game. It's unnecessary and will lead to inconsistent states across multiple objects.
Make your constructor private - unless I'm missing something, there's no reason to initialize it outside of the factory.
private TicTacToe(int size) {
game = new String[size][size];
}
Or, better yet:
private TicTacToe(String[][] hydratedBoard) {
game = hydratedBoard;
}
I'll show you why in a moment.
Implement TicTacToe.create(String), and return the fully hydrated object. A suggestion would be to create the String[][] implicitly, create the object with that passed in as an argument to the constructor, and return your TicTacToe object.
public static TicTacToe create(String input) {
String[][] board = new String[3][3];
int i = 0; // count the row we're on
String[] tokens = input.split(",");
for(int j = 0; j < board.length; j++) {
if (j % 3 == 0) { // advanced to the end of the column set (SO)
i++;
}
board[i][j] = tokens[i*3 + j];
}
return new TicTacToe(board);
}
Provide some sort of getter to the board object. You might not have to do this per the assignment, but it's good practice. It could be either a straight-up getter on the String[][], or some sort of pretty-print representation; I don't know. I'll leave this implementation to the reader instead.
You're overthinking it. Rather than "return null;", use "return new TicTacToe(size);".
Although, usually when I create a static factory method (like your "create" method) I make the constructor private so it can only be called from the static create method.
...and then you will need to update the board if you want to actually remember the x/o positions you passed in...
Here I added an integration test for this game that might give you some ideas of how to create/think about the game.
public void testWinnerPlayerIWithVerticalLine() {
this.displayUnitTestDescription("Integration Test for having player 'X' as winner on a vertical line use case");
final IBoardGame<TicTacToeMove, TicTacToePlayer> ticTacTocGame = new TicTacToeGame();
final String playerIDisplayName = "X";
final String playerIIDisplayName = "O";
final TicTacToePlayer playerI = new TicTacToePlayer(playerIDisplayName);
final TicTacToePlayer playerII = new TicTacToePlayer(playerIIDisplayName);
ticTacTocGame.setGamePlayers(new TicTacToePlayer[]{playerI, playerII});
TicTacToePlayer[][] expectedBoardInteractionSnapshot = new TicTacToePlayer[][]{
new TicTacToePlayer[]{playerI, null, playerII},
new TicTacToePlayer[]{playerI, playerII, null},
new TicTacToePlayer[]{playerI, playerII, playerI}
};
ticTacTocGame.start();
ticTacTocGame.makeMove(new TicTacToeMove(0, 0));
ticTacTocGame.makeMove(new TicTacToeMove(1, 1));
ticTacTocGame.makeMove(new TicTacToeMove(2, 2));
ticTacTocGame.makeMove(new TicTacToeMove(0, 2));
ticTacTocGame.makeMove(new TicTacToeMove(2, 0));
ticTacTocGame.makeMove(new TicTacToeMove(2, 1));
ticTacTocGame.makeMove(new TicTacToeMove(1, 0));
this.displayBoardPlayerInteractionSnapshot(ticTacTocGame);
final TicTacToePlayer[][] actualBoardInteractionSnapshot = ticTacTocGame.getPlayerInteractionSnapshotBoard();
Assert.assertFalse(ticTacTocGame.isGameDraw());
Assert.assertTrue(ticTacTocGame.existWinner());
Assert.assertEquals(ticTacTocGame.getWinner().getDisplayName(), playerIDisplayName);
Assert.assertArrayEquals(actualBoardInteractionSnapshot, expectedBoardInteractionSnapshot);
}
If you are interested to find out more you can find the whole java implementation of the TicTacToe game: https://github.com/ncaralicea/tictactoe

How do I clone an object for the purposes of moving something and seeing if the move is valid? (Java, Chess)

I am writing a simple chess-playing game. I won't post it all here, but I'll give you the necessary details.
I move by clicking a square with a piece on it, then the square becomes selected, and then clicking where I want to piece to move. Sometimes in chess, a move may fail to respond to check or create a check on one's own king and is therefore illegal. The best way, I've found, to decide whether a move is illegal is to make a move on an "ifBoard" (a clone of the board) and if I deem the move legal, set the real board equal to the ifBoard.
Here is a code snippet of me responding to mouse clicks (board is the real board, destination is the clicked square, selectedSquare is the square previously selected(if not null))
public void mousePressed(MouseEvent e){
Square selectedSquare = board.selectedSquare();
Square destination = board.getSquare(e.getX(), e.getY());
board.deselect();
if(destination == null){
repaint();
return;
}
if(selectedSquare == null){
System.out.println("SelectedSquare is null");
if(destination.occupiedByTeam(turn)){
System.out.println("destination is occupied by right team and is null");
board.select(destination);
}
}
else{
if(!selectedSquare.occupiedByTeam(turn)){
System.out.println("SelectedSquare not occupied by correct team");
repaint();
return;
}
if(destination.occupiedByTeam(turn)){
System.out.println("ChosenSquare occupied by same team");
board.select(destination);
repaint();
return;
}
//move on a dummy board and check for conflicts
Board ifBoard = (Board)board.clone();
System.out.println(ifBoard.toString());
System.out.println(board.toString());
//check if you can't move due to piece movement limitations
//.place() is a coordinate of the square on the tile system (A-H and 1-8)
if(
!ifBoard.move((int)selectedSquare.place().getX(), (int)selectedSquare.place().getY(), (int)destination.place().getX(), (int)destination.place().getY())
){
repaint();
return;
}
//if moving results in self-check
if(ifBoard.check(turn)){
//don't move
repaint();
return;
}
else{
//move
System.out.println("Board moved!");
board = new Board(ifBoard);
cycleTurns();
}
}
repaint();
}
The toString calls are registering differently, but I have narrowed the problem down to the ifBoard.move() call actually moving the real board.
Here is the board class, or part of it.
import java.awt.Color;
import java.lang.Cloneable;
import java.awt.geom.*;
import java.awt.Graphics;
import java.awt.Graphics2D;
public class Board implements Cloneable{
private Square[][] squares;
private Rectangle2D squareWrap;
private Rectangle2D boardBorder;
private Square selectedSquare;
public Board(){
squares = new Square[8][8];
for(int i = 0; i < 8; i++){
for(int j = 0; j < 8; j++){
squares[i][j] = new Square(new Point2D.Double(i, j));
}
}
boardBorder = new Rectangle2D.Double(Constants.boardX,
Constants.boardY,
Constants.borderWidth * 2 + Constants.boardSide,
Constants.borderHeight * 2 + Constants.boardSide);
squareWrap = new Rectangle2D.Double(Constants.boardX + Constants.borderWidth,
Constants.boardY + Constants.borderHeight,
Constants.boardSide,
Constants.boardSide);
selectedSquare = null;
}
public Object clone() {
Board obj = new Board();
obj.setSquares(this.squares);
obj.setSelectedSquare(this.selectedSquare);
return obj;
}...
Am I cloning incorrectly? Is there a better way? Thank you in advance.
Am I cloning incorrectly? Is there a better way?
The clone method should always start by calling super.clone() for reasons that I won't go into in this post.
Also, you're not cloning the attributes of the object (you're doing a shallow copy instead of a deep copy). Thus a cloned Board would share the same reference to the squares structure. (Changing the cloned Board would change the original Board.)
(Many people argue that you should avoid clone and Cloneable all together though.)
If I were you, I would strongly consider making the Board class immutable and perhaps go with some copy-on-write mechanism. That would save you a lot of headache I believe.
Your Problem might be that your clone() implementation does not create a deep copy. The cloned object shares a least some state with the instance it is cloned from. By that, I mean they are referencing the same objects:
public Object clone() {
Board obj = new Board();
obj.setSquares(this.squares); // Square instances are the same for both boards
return obj;
}
If you change state on the clone - e.g. on a square - you also change it on the real board.
From what you've posted, you are calling ifBoard.move(). If that method affects part of the "shared state" then it will affect both board instances.

Trying to avoid a Force close after a bullet goes off screen

So I'm just messing around learning to create a Space invaders type game. I can get the bad guys to move, Great!!. Hero moves, Great!! Bullets move, Great!! However I try to remove my bullets once they leave the screen as to not eat up all resources and it force closes on me once it gets rid of the bullet. It goes off the screen. Hits the int of -2 and then we use the remove() and boom. Force Close.
Here is my code. I'm wondering if they access the size() at the same time and just cause a force close because of it.
//I removed everything that doesn't pertane to the bullets.
public class GameScreen{
Bullet bullet = world.bullet;
public GameScreen(Game game) {
super(game);
world = new World();
}
//Draws our bullets.
int bulletLength = bullet.bullets.size();
for(int i = 0; i < bulletLength; i++) {
Placement part = bullet.bullets.get(i);
x = part.x * 32 + 11;
y = part.y * 32;
g.drawPixmap(Assets.bullet, x, y);
}
Class that holds my bullets.
public class Bullet {
public List<Placement> bullets = new ArrayList<Placement>();
public Bullet() {
}
public void shoot(int x, int y){
bullets.add(new Placement(x,y));
}
public void advance(){
int len = bullets.size(); // gets all bullets.
for(int i = 0; i < len; i++) {
bullets.get(i).y --;
if (bullets.get(i).y <= -2){//removes them once they are off the screen.
bullets.remove(i);
}
}
}
This is what I use to keep track of placement.
package com.learning.planecomander;
public class Placement {
public int x, y;
public Placement(int x, int y) {
this.x = x;
this.y = y;
}
}
When going through your list to remove bullets, you can remove bullets from a list but that affects the list immediately instead of after your loop is done. Since you are traversing to the length of the list at the start, you are going off the end of the list since you've removed elements. An example is probably more helpful than that description.
Let's say you have a list with three bullets (which I'll call a, b, c to make the example easier). On a pass through the list, a and c are fine but b needs to be removed.
i = 0;
bullets[0] = a;
bullets[1] = b;
bullets[2] = c;
First loop goes fine, second loop starts like this
i = 1;
bullets[0] = a;
bullets[1] = b;
bullets[2] = c;
We remove b, but the loop keeps going
i = 2;
bullets[0] = a;
bullets[1] = c;
OH CRAP ARRAYINDEXOUTOFBOUNDS! PROGRAM CRASHES!
The way to solve this is to use a temp list to store the bullets that need to be removed, and then once your update loop is finished, make a call to bullets.removeAll(temp)
Doing two passes is a good answer. It makes the loops simpler and easy to understand. If you'd like to do it in one pass though, iterate through the list in reverse order, and when you remove a bullet you can go to the next one and not worry about blasting past the end of the ArrayList.
Alternatively, you can keep your bullets in a linked list, and run through the list with an Iterator, which you can also use to remove items from the list with. Removing from the beginning middle or end of an linked list is always a constant time operation. Whereas removing from the beginning of an ArrayList can be more expensive. If you need random access to the elements in the list, then they can be inefficient. Keep in mind though, if you're only dealing with a handful of objects, then it doesn't really matter.
For bonus points, you might want to put all of your objects in a list, and then have your central loop process them all and have your game objects respond polymorphically to calls like dead?, think, move, draw or whatever you think is appropriate.

Categories

Resources