Remove Items While Iterating List In Java

Edit: Some (better) alternatives here and here

Edit 2: @kattehus was awesome enough to compare the three methods. 1) my graveyard method, 2) Joe’s iterator method, and 3) Kattehus’ standard for-loop method. Go with the standard for-loop. I’ll leave the rest of my post so others can see one method of doing so, though it’s not the best method.

1
2
3
4
5
6
for (int i = items.size()-1; i >= 0; i--) {
	SomeItem item = items.get(i);
	if (item.value < 25) {
		items.remove(i);
	}
}

End of edit 2.

So you have a list of something and you want to remove some of those things from the list. So you loop through them, check to see if the item should be removed, and you remove it from the list.

*CRASH*

What happened? You likely ended up with the following stack trace.

java.util.ConcurrentModificationException
 at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:819)
 at java.util.ArrayList$Itr.next(ArrayList.java:791)
 at RemoveFromListExample.thisWillNotWork(RemoveFromListExample.java:36)
 at RemoveFromListExample.<init>(RemoveFromListExample.java:13)
 at RemoveFromListExample.main(RemoveFromListExample.java:79)

Oops. So what went wrong? As far as Java sees it, it was happily looping through the list of items, knowing exactly how many items were in the list, when suddenly the list size changed. Java didn’t like that and so it put an end to the loop.

But you still need to remove those things from that list. What do you do? Build a second list!

I like to call the second list the “graveyard”. Basically, loop through the list and when you find something you want removed from the list just add it to the graveyard. Outside the loop just tell the first list to remove all items found in the second list. Like this:

1
2
3
4
5
6
7
8
9
public void thisOneWorks(List<SomeItem> items) {
	List<SomeItem> graveyard = new ArrayList<SomeItem>();
	for (SomeItem item : items) {
		if (item.value < discardBelowValue) {
			graveyard.add(item);
		}
	}
	items.removeAll(graveyard);
}

Below is the full source code for an example of what does and does not work, followed by the output of the program. Give it a try to see for yourself. It’s not limited to ArrayList, either. It also works with LinkedList and I presume whatever else you find in Collections.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
import java.util.ArrayList;
import java.util.List;
 
public class RemoveFromListExample {
 
	protected int discardBelowValue;
 
	public RemoveFromListExample(int discardBelowValue) {
 
		this.discardBelowValue = discardBelowValue;
 
		try {
			thisWillNotWork(getList());
		} catch (Exception e) {
			e.printStackTrace();
		}
 
		thisOneWorks(getList());
	}
 
	public List<SomeItem> getList() {
		List<SomeItem> items = new ArrayList<SomeItem>();
 
		items.add(new SomeItem("Penny", 1));
		items.add(new SomeItem("Nickle", 5));
		items.add(new SomeItem("Dime", 10));
		items.add(new SomeItem("Quarter", 25));
		items.add(new SomeItem("Dollar", 100));
 
		return items;
	}
 
	public void thisWillNotWork(List<SomeItem> items) {
		printList(items);
		System.out.println("Try to delete while iterating...");
		for (SomeItem item : items) {
			if (item.value < discardBelowValue) {
				items.remove(item);
			}
		}
		printList(items);
	}
 
	public void thisOneWorks(List<SomeItem> items) {
		printList(items);
		System.out.println("Delete after iterating...");
		List<SomeItem> graveyard = new ArrayList<SomeItem>();
		for (SomeItem item : items) {
			if (item.value < discardBelowValue) {
				graveyard.add(item);
			}
		}
		items.removeAll(graveyard);
		printList(items);
	}
 
	public void printList(List<SomeItem> items) {
 
		System.out.println("Items in list");
		for (SomeItem item : items) {
			System.out.println(" * " + item.name + " (" + item.value + ")");
		}
	}
 
	private class SomeItem {
 
		protected String name;
		protected int value;
 
		public SomeItem(String name, int value) {
			this.name = name;
			this.value = value;
		}
 
	}
 
	public static void main(String[] args) {
		int discardBelowValue = 25;
		System.out.println("Discard below " + discardBelowValue + " cents");
		new RemoveFromListExample(discardBelowValue);
	}
 
}

Output:

Discard below 25 cents
Items in list
 * Penny (1)
 * Nickle (5)
 * Dime (10)
 * Quarter (25)
 * Dollar (100)
Try to delete while iterating...
java.util.ConcurrentModificationException
	at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:819)
	at java.util.ArrayList$Itr.next(ArrayList.java:791)
	at RemoveFromListExample.thisWillNotWork(RemoveFromListExample.java:36)
	at RemoveFromListExample.(RemoveFromListExample.java:13)
	at RemoveFromListExample.main(RemoveFromListExample.java:79)
Items in list
 * Penny (1)
 * Nickle (5)
 * Dime (10)
 * Quarter (25)
 * Dollar (100)
Delete after iterating...
Items in list
 * Quarter (25)
 * Dollar (100)

Ranking Players and Declaring a Winner

I’ve written about comparators once before but only just realized that the usefulness of that post hinges on the availability of the site it links to. Not wanting to rely on a third party site and the owner’s ability to pay hosting fees, here’s my quick blurb on how comparators work in Java.

But first, why do I need a comparator in the first place? Simply put, to declare a winner at the end of a round of Board Rogue. When a player reaches the board’s exit, the game is over. Scores are tallied, players are ranked, and the player with the highest score wins.

So you know how to sort numbers. You probably know how to sort alphabetically. There are functions for that sort of stuff built into most every programming language. But how do you take something like a PLAYER and sort them? You use a custom comparator, and the Collections class.

So you’ve got a player.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class Player {
 
	private int score;
	private String name;
 
	public Player(String name) {
		this.name = name;
	}
 
	public int getScore() {
		return score;
	}
 
	public void setScore(int score) {
		this.score = score;
	}
}

And the game itself has a list of Players.

List<Player> playerList = new ArrayList<Player>();

And through the course of the game, each player accumulates a varied amount of treasure and items. Each piece of loot has a value associated with it, and the player with the highest loot value wins.

You could just loop through all of the players, look for the highest score, and declare a winner. But what’s the fun in that? You can’t easily tell who’s in second, third, or last place. But you can if you sort them! So create a comparator class that we’ll use to compare scores.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class PlayerScoreComparator implements Comparator<Player> {
 
	public int compare(Player p1, Player p2) {
 
		int p1score = p1.getScore();
		int p2score = p2.getScore();
 
		if (p1score > p2score)
			return -1;
		else if (p1score < p2score)
			return 1;
		else
			return 0;
	}
 
}

And now, to sort the playerList, simply apply the comparator to the Collection.sort function.

Collections.sort(playerList, new PlayerScoreComparator());

Finally, putting it all together you get the following.

Code.

1
2
3
4
5
6
7
8
9
for (Player player : playerList) {
	System.out.println ("Unsorted " + player.getName() + " has " + player.getScore() + " points");
}
 
Collections.sort(playerList, new PlayerScoreComparator());
 
for (Player player : playerList) {
	System.out.println ("Sorted " + player.getName() + " has " + player.getScore() + " points");
}

Output.

Unsorted Player One has 116 points
Unsorted Player Two has 616 points
Unsorted Player Three has 129 points
Sorted Player Two has 616 points
Sorted Player Three has 129 points
Sorted Player One has 116 points

New Game: Board Rogue

I’ve started on my next game. At the moment it’s called Board Rogue, though that’s subject to change. I said the same thing about Squishy Bugs. Squishy Bugs was supposed to be the code-name for the project, like Helicopter Ninja and Space Fight before it. But Squishy Bugs stuck, and who knows if Board Rogue is going to get another name by the time it ships. The name is really growing on me.

So I’m feeling a little inspired by this article on open board game design. It basically boils down to don’t be afraid to openly share your game’s development because other people are too busy working on their own killer game and ideas area cheap. At least that’s what I got out of it. So without further ado, here’s a little glimpse into what Board Rogue is going to be about.

First, a couple definitions.

Board game
 A board game is a game that involves counters
 or pieces moved or placed on a pre-marked
 surface or "board", according to a set of rules.
Roguelike
 The roguelike is a sub-genre of role-playing
 video games, characterized by level
 randomization and permanent death.

So what is Board Rogue?

A board game, played on a single Android tablet, played by and passed between 1 to 6 players. Players take turns rolling dice to traverse the randomly generated dungeon in search of the big treasure at the end of the board.

There are currently only 4 types of “squares” that make up the board. Each square is a type of room. Either empty, monster, trap, or treasure.

Empty rooms are just that. Generally safe rooms that don’t help or hinder player progress.

Monster rooms are occupied by monsters. Landing in a monster room prompts you to fight with the monster. Killing the monster rewards the player with loot which may alter the player’s skills when used. It’s not in place yet but there will probably be an option to flee the fight if the battle is going poorly for you. Player death sends the player back to the board’s entrance. And they drop all of their loot on the floor of the monster’s room. The good news, the monster remains hurt so anyone else who comes across that monster square later will have an easier fight… unless the monster has regenerative abilities. Trolls typically regenerate when not in battle, so be aware!

Trap rooms mostly do bad things to players. They might cause the player to lose a turn, go back 2 squares, or take damage. If a trap kills you then you drop your loot and go back to the beginning of the board. Noticing a theme here?

Death is permanent. Your hero dies and you go back to the beginning of the board as a brand new hero with no special loot or skills.

Last, the treasure room. The game is points based, where the player with the highest score at the end of the game wins. Treasure counts toward your total points. A bar of gold might be worth 750 points. A small gem might be worth 100. But treasure rooms aren’t limited to jewellery and gems. Players might get lucky and find special armor or a weapon. Or an unset trap…

Unset traps are the game’s way of allowing a player to hinder other players. When a player is in an empty room, and they have an unset trap in their inventory, the player can trap that room. That room will remain a safe room for that player, for the duration of their hero’s life. The trap springs only for a hero that didn’t set the trap. In most cases this means all of the other players, but what if the trap’s hero dies? Then the trap is now hostile toward that player’s new hero as well.

So that’s the general outline of the game. Take your turn, pass the tablet to the next player, and so on. Collect as many points as you can before someone reaches the exit. Highest score wins the game.

Stay tuned for more Board Rogue tidbits as development continues. As usual you can follow along with the game’s development at the task tracker or discuss it at the WaggSoft Forums.

Find me as @kdnewton on Twitter and the WaggSoft Facebook page.

PHP, curl and SSL23_GET_SERVER_HELLO

Using the following curl block I was getting an unexpected response from the server.

1
2
3
4
5
6
7
$ch = curl_init($post_url);
curl_setopt( $ch, CURLOPT_POST, 1 );
curl_setopt( $ch, CURLOPT_POSTFIELDS, "orderXML=".$xmlRequest );
curl_setopt( $ch, CURLOPT_RETURNTRANSFER, 1 );
curl_setopt( $ch, CURLOPT_TIMEOUT, 3000 );
curl_setopt( $ch, CURLOPT_VERBOSE, 1 );
$xmlResponse = curl_exec( $ch );

Pretty simple call. It’s attempting to communicate with an url over https which is where the problem lies. Here is the response I was receiving.

1
2
Curl error number: 35
Curl error: error:14077410:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure

Simple call. Confusing problem. Simple solution. Add the following line before the curl_exec.

1
curl_setopt($ch, CURLOPT_SSLVERSION, 1);

Checking the documentation, it says this: CURLOPT_SSLVERSION – The SSL version (2 or 3) to use. By default PHP will try to determine this itself, although in some cases this must be set manually.

I tried setting the value to 2 but it didn’t work.

1
2
Curl error number: 4
Curl error: OpenSSL was built without SSLv2 support

And setting it to 3 didn’t either.

1
2
Curl error number: 35
Curl error: error:1408F10B:SSL routines:SSL3_GET_RECORD:wrong version number

I wish I could tell you why setting it to 1 worked for me, but I don’t understand it. It just works for me where the documented values do not.

Fit Width of Background Image But Keep Aspect Ratio in Android

So you have an image that you want to use as a background on one of your activities.

android_01

 

You probably have something that looks like this.

android_scale_01

But the desired effect is to scale the original image into the blue outline below.

android_02

The actual effect (depending on your current layout)  is the graphic anchored to the top left (android:scaleType=”fitStart”) or center (android:scaleType=”fitCenter”) of the device’s screen with no scaling performed. Through all of your research on Google (directing you mostly to Stack Overflow threads) you’re stuck with a non-scaling graphic that’s positioned incorrectly on the screen. Or maybe you’ve got a distorted graphic that has stretched both in length and width and looks terrible. The short answer?

You can not scale the width of an ImageView to the screen’s resolution while maintaining aspect ratio in an Android layout using only XML.

That’s the information I got from one of the random Stack Overflows I found. And I ignored it for quite a while before giving in and trying to scale the image manually through code.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >
 
    <LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="fill_parent" >
 
        <ImageView
            android:id="@+id/iv_background"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:scaleType="fitCenter"
            android:src="@drawable/the_background" />
    </LinearLayout>
 
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical" >
 
        <Button
            android:id="@+id/b_login"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="50dp"
            android:text="@string/login_button" />
    </LinearLayout>
 
</RelativeLayout>

And the necessary code placed at the bottom of the activity’s onCreate method.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
DisplayMetrics metrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metrics);
int height = metrics.heightPixels;
int width = metrics.widthPixels;
 
BitmapDrawable bmap = (BitmapDrawable) this.getResources().getDrawable(R.drawable.the_background);
float bmapWidth = bmap.getBitmap().getWidth();
float bmapHeight = bmap.getBitmap().getHeight();
 
float wRatio = width / bmapWidth;
float hRatio = height / bmapHeight;
 
float ratioMultiplier = wRatio;
// Untested conditional though I expect this might work for landscape mode
if (hRatio < wRatio) {
	ratioMultiplier = hRatio;
}
 
int newBmapWidth = (int) (bmapWidth*ratioMultiplier);
int newBmapHeight = (int) (bmapHeight*ratioMultiplier);
 
ImageView iView = (ImageView) findViewById(R.id.iv_background);
iView.setLayoutParams(new LinearLayout.LayoutParams(newBmapWidth, newBmapHeight));

android_scale_02

This results in an ImageView that’s stretched to fit the width of the screen while maintaining the aspect ratio of the image.

Staypressed theme by Themocracy