Judging Results

I’m working on this, along with a lot of other statistical analysis. It’s interesting to note that appel has the largest variance in scores in all categories.

I admit this is a problem. The reviews got finished so late that there was little time for afterthoughts.

I am now pondering with the idea of skipping these zero scores, and only averaging the score that is above zero. This WILL affect the order of the games, even in the top 10 and even in the top 3, although the #1st place is firmly held by Left 4k dead.

I can easily correct this, and in fact have the code ready for it, but I need “go ahead” from you guys.

Just do it ™.

However you should probably also put up the following variants:

  • Remove all the highest scores for each entry
  • Remove all the lowest scores for each entry
  • Remove all both the highest and the lowest for each entry
  • Remove a particular judge’s results for each entry
  • Make all the scores for every game but the one selected zero (ok, maybe not this one ;)).

It’d hardly be fair to judge some entries on 4 judge’s results and some on 5 given the disparity in the judges ranges of scores and approach to judging.

This could go on and on and on…

One could also argue that it’s a coding contest and failing with an NPE is a failure to code to some API or framework given how many other games managed to run on the same setup.

Kev

Without any hesitation, go ahead, appel ! Skipping these zero scores would be fairer for everyone.

And too bad for me if my own game looses thirty places ! :o ( humor of course… )

Morre helped me realize this problem, and I’ve taken the steps to correct it.

The score chart has now been corrected!

This is entirely my fault, so anyone who now sees his game drop a few spots can only blame me. But in the end, I think this is more fair for a whole lot people.

I would certainly appreciate it, appel. Let’s see what the rest of the community thinks. Perhaps a poll?

EDIT:

I see you just changed it. Thanks a bunch!

Please, just keep in mind that I want the community to have a say in this! If they preferred the old version, I will accept it (although I don’t have to like it!). I don’t want to be the one ruining the contest for somebody. :slight_smile:

No, this was clearly an error, which has now been corrected.

An error doesn’t become an mistake until you refuse to correct it, and I don’t want to make this into a mistake.

Oh, I forgot:

Congratulations, Markus!

Left 4k Dead was a very worthy winner, and one of the best 4k games to date. Well done!

EDIT:
Also, I would again like to thank all the judges and the organizers for amazing work! I’ve had a lot of fun this year (as always!) :slight_smile:

I almost forgot also:

Congratulations to the WINNERS and all the game developers! Hopefully you’ll participate again next year :wink:

Omg, yay! =D
I’m SO spending all day tomorrow bragging.

I love the reviews, they’re very detailed and shows that the judges actually care about the games they’re judging. Thanks for putting in the effort, and a BIG thanks to appel.

So what am I supposed to do until Java4k 2010? :-\

The way to handle the disparity in ranges of scores is to normalise. Doing that and discounting 0s gives:

Sorting category Overall by Normalised means ignoring zeros
 1. Left 4k Dead                            94.5
 2. 4bidden Fruit                           90.1
 3. Bridge4k                                88.8
 4. Pixeloids4k                             88.2
 5. Hunt 4k Bread                           86.4
 6. Keggle                                  85.1
 7. Robo rampage                            84.1
 8. jm00 - a boomshine clone in 4k v1.2     84.0
 =  Red Baron 4K                            84.0
10. Fortress4K                              83.5
11. Splosh4k                                82.9
12. Putty Shuffle                           82.3
13. World Rally Driver 4k                   82.0
14. Tekicars4k                              81.6
15. Just Get Bigger 4K                      81.4
16. BlockBuster4k                           80.3
17. NiGHTS 4k                               79.8
18. MEG4kMAN                                79.1
19. Q*Bert4K                                78.7
20. Conquest of Planets                     78.5
21. Invaders                                78.2
22. RevolvoMan-4K                           77.8
23. 4x4k                                    77.5
24. Jetp4k                                  76.4
25. 4bsolution                              75.9
26. Space Paranoids 2D4K                    75.6
27. Critters4k                              75.5
 =  Ice Fighters                            75.5
29. F-Zero 4K                               75.4
30. Kart                                    74.6
31. J-Type                                  74.5
32. Asteroid Alert!                         74.4
33. Run Over Zombies                        74.0
34. Super Marble World                      73.2
35. Sea Spin                                72.8
36. Word Twister                            72.3
37. Sea through                             70.5
38. RhythmSphere                            69.8
39. Treasure4k                              69.5
40. submarin                                68.1
41. Bio 4K                                  67.3
42. HexoDama                                66.6
43. Honey4kKeeper                           66.1
44. Doodles                                 66.0
45. Grasshopper4k                           65.6
46. Crimsonland4k version 1.001             65.5
47. Alienz 4K                               64.5
 =  Star 4x                                 64.5
49. Crack Tower Defense                     63.2
50. Gravitational Fourks                    61.2
51. Ultimate Tic-Tac-Toe                    60.9
52. Anyone 4 Tennis?                        59.8
 =  PacPitfall4k                            59.8
54. Coffee Shop Puzzle                      59.0
55. Infinite Platformer 4k                  57.0
56. Frequent Flier                          56.4
57. Deathchase                              55.5
58. BlisterBall                             53.0
59. Scr4mble                                52.5
60. Dragon 4k Boxing                        52.2
61. Arena4k                                 51.9
62. Beez Helper                             51.6
63. i4kopter                                50.6
64. QuadSquad4k                             50.1
65. Virtual On 4k                           44.3
66. 4K Maze                                 37.5
67. Desert Bus                              24.7

Code to follow, because it doesn’t fit in one post.

[quote]One could also argue that it’s a coding contest and failing with an NPE is a failure to code to some API or framework given how many other games managed to run on the same setup.
[/quote]
The fact that you don’t know which API or framework is a hint that it’s not necessarily the coder’s fault. My game broke with a version of Java which was released after I finished writing it. I don’t know which API or framework broke, nor in what way, because Webstart is rather sparse with its error messages. The only error message it shows seems to be an internal one.

Had to split it because of message length restrictions. See the TODO.

import java.util.*;
public class Analyse4k{
	private static String[] areaNames={"Overall","Technical","Presentation"};
	public static void main(String[] args){
		// Note: values extracted automatically from the HTML page.
		List<Game> games=new ArrayList<Game>();
		// TODO Copy lines from next post here.

		// Analysis by category. Ignore zeros.
		double[][]areaJudgeMeans=new double[3][5];
		double[][]areaJudgeVars=new double[3][5];
		for (int area=0;area<3;area++){
			for (int judge=0;judge<5;judge++){
				int t=0,t2=0,n=0;
				for (Game game:games){
					int val=game.scores[area][judge];
					if (val!=0){t+=val;t2+=val*val;n++;}
				}
				double mu=t/(double)n;
				double var=(t2/(double)n)-mu*mu;
				areaJudgeMeans[area][judge]=mu;
				areaJudgeVars[area][judge]=var;
			}
		}

		// Original values:
		//printResults(games,new SimpleMean(),0);

		// Current values:
		//printResults(games,new MeanIgnoringZeros(),0);

		// Fairest algorithm, assuming there should be no penalty for scoring 0s?
		printResults(games,new NormalisedMeansIgnoringZeros(areaJudgeMeans[0],areaJudgeVars[0]),0);
	}

	private static void printResults(List<Game> games, ScoreAlgorithm alg, int area){
		Collections.sort(games,new GameComparator(alg,area));
		int longestName=0;
		for (Game game:games) if (game.name.length()>longestName) longestName=game.name.length();

		System.out.println("Sorting category "+areaNames[area]+" by "+alg);
		int prev=Integer.MAX_VALUE,i=0;
		for (Game game:games){
			i++;
			int score=alg.score(game,area);
			String pos=score==prev?"= ":(i+".");
			System.out.print(pad(3-pos.length())+pos+" "+game.name+pad(longestName+4-game.name.length()));
			String sc=(score/10)+"."+(score%10);
			System.out.println(pad(5-sc.length())+sc);
			prev=score;
		}
	}

	private static String pad(int n) {
		char[] foo=new char[n];
		Arrays.fill(foo,' ');
		return new String(foo);
	}

	private static class Game {
		public String name;
		public int[][] scores=new int[3][5];

		public Game(String name,int[][] scores){
			this.name=name;
			this.scores=scores;
		}
	}

	public static interface ScoreAlgorithm {
		public abstract int score(Game game, int area);
	}

	public static class GameComparator implements Comparator<Game> {
		private final int area;
		private final ScoreAlgorithm alg;

		public GameComparator(ScoreAlgorithm alg,int area) {
			this.alg=alg;
			this.area=area;
		}

		public int compare(Game g1,Game g2) {return alg.score(g2,area)-alg.score(g1,area);}
	}

	public static class SimpleMean implements ScoreAlgorithm {
		public int score(Game game,int area) {
			int total=0;
			for (int i=0;i<5;i++) total+=game.scores[area][i];
			return (total*10+2)/5;
		}

		public String toString() {return "Simple mean";}
	}

	public static class MeanIgnoringZeros implements ScoreAlgorithm {
		public int score(Game game,int area){
			int total=0,n=0;
			for (int i=0;i<5;i++) if (game.scores[area][i]!=0) {total+=game.scores[area][i];n++;}
			return (total*10+n/2)/n;
		}

		public String toString() {return "Mean ignoring zero values";}
	}

	// Normalise to mean 70, variance 250.
	public static class NormalisedMeansIgnoringZeros implements ScoreAlgorithm {
		private final double[] means;
		private final double[] vars;

		public NormalisedMeansIgnoringZeros(double[] means,double[] vars) {
			this.means=means;
			this.vars=vars;
		}

		public int score(Game game,int area) {
			double total=0,n=0;
			for (int i=0;i<5;i++) {
				if (game.scores[area][i]!=0) {total+=70+(game.scores[area][i]-means[i])*250/vars[i];n++;}
			}

			return (int)(10*total/n+.5);
		}

		public String toString() {return "Normalised means ignoring zeros";}
	}
}

That may be a hint to you, but the end user doesn’t give a rats ass do they. They click the link and it didn’t work. The fact its an NPE is a hint it is coder error. All of that’s beside the point now really isn’t it, the contest is over, the results are finalized.

Kev

		games.add(new Game("4bidden Fruit", new int[][]{{96,76,90,100,90},{97,70,90,86,90},{96,84,85,96,90}}));
		games.add(new Game("4bsolution", new int[][]{{91,65,70,80,90},{98,60,75,80,85},{98,80,70,99,80}}));
		games.add(new Game("4K Maze", new int[][]{{30,50,20,72,70},{15,55,20,74,70},{10,50,20,1,60}}));
		games.add(new Game("4x4k", new int[][]{{67,80,70,82,92},{83,85,75,90,85},{70,85,70,90,80}}));
		games.add(new Game("Alienz 4K", new int[][]{{53,82,55,92,70},{63,75,55,75,65},{60,85,55,75,70}}));
		games.add(new Game("Anyone 4 Tennis?", new int[][]{{60,65,70,62,70},{62,82,75,84,80},{75,80,65,79,65}}));
		games.add(new Game("Arena4k", new int[][]{{69,62,60,75,50},{62,73,60,60,55},{55,70,60,40,50}}));
		games.add(new Game("Asteroid Alert!", new int[][]{{59,82,80,87,75},{78,92,80,94,65},{60,87,75,94,75}}));
		games.add(new Game("Beez Helper", new int[][]{{45,60,40,86,70},{50,73,45,75,65},{55,64,55,89,70}}));
		games.add(new Game("Bio 4K", new int[][]{{54,93,70,68,70},{50,97,60,72,65},{60,90,60,81,65}}));
		games.add(new Game("BlisterBall", new int[][]{{62,40,80,62,60},{50,50,75,45,65},{40,40,75,15,50}}));
		games.add(new Game("BlockBuster4k", new int[][]{{48,92,80,92,85},{46,85,70,86,85},{55,82,80,93,85}}));
		games.add(new Game("Bridge4k", new int[][]{{92,90,0,92,90},{92,92,0,100,95},{70,80,0,89,85}}));
		games.add(new Game("Coffee Shop Puzzle", new int[][]{{78,45,75,72,65},{68,75,70,86,65},{84,83,80,89,75}}));
		games.add(new Game("Conquest of Planets", new int[][]{{92,82,75,82,80},{80,88,80,71,80},{80,78,70,68,75}}));
		games.add(new Game("Crack Tower Defense", new int[][]{{65,69,75,62,70},{40,79,75,78,75},{30,74,70,45,65}}));
		games.add(new Game("Crimsonland4k version 1.001", new int[][]{{67,58,70,86,0},{55,50,80,82,0},{48,50,65,82,0}}));
		games.add(new Game("Critters4k", new int[][]{{84,72,85,89,70},{95,78,75,90,75},{60,68,75,55,70}}));
		games.add(new Game("Deathchase", new int[][]{{60,57,70,70,60},{65,70,75,65,60},{70,80,65,70,60}}));
		games.add(new Game("Desert Bus", new int[][]{{65,65,20,5,50},{55,75,10,30,50},{55,72,40,50,50}}));
		games.add(new Game("Doodles", new int[][]{{72,85,70,78,60},{75,94,80,89,75},{62,83,65,80,55}}));
		games.add(new Game("Dragon 4k Boxing", new int[][]{{18,73,60,70,65},{25,70,70,80,65},{38,82,60,90,65}}));
		games.add(new Game("F-Zero 4K", new int[][]{{66,90,75,66,85},{67,90,80,84,75},{78,85,75,87,90}}));
		games.add(new Game("Fortress4K", new int[][]{{94,92,70,81,90},{88,95,70,86,85},{82,92,75,89,80}}));
		games.add(new Game("Frequent Flier", new int[][]{{25,78,0,68,0},{45,88,0,91,0},{25,75,0,42,0}}));
		games.add(new Game("Grasshopper4k", new int[][]{{68,82,60,60,80},{70,89,60,78,80},{75,87,65,88,85}}));
		games.add(new Game("Gravitational Fourks", new int[][]{{70,66,0,65,0},{73,50,0,68,0},{65,70,0,61,0}}));
		games.add(new Game("HexoDama", new int[][]{{72,86,80,45,70},{83,85,75,76,75},{64,80,75,74,65}}));
		games.add(new Game("Honey4kKeeper", new int[][]{{42,83,65,81,75},{40,86,65,73,70},{45,90,65,89,75}}));
		games.add(new Game("Hunt 4k Bread", new int[][]{{82,82,80,91,95},{90,91,70,88,95},{68,87,75,90,90}}));
		games.add(new Game("i4kopter", new int[][]{{56,63,65,40,65},{58,68,65,70,70},{42,72,60,55,60}}));
		games.add(new Game("Ice Fighters", new int[][]{{92,86,70,80,75},{98,90,75,89,75},{92,93,75,82,75}}));
		games.add(new Game("Infinite Platformer 4k", new int[][]{{48,0,70,74,60},{30,0,75,72,55},{38,0,75,70,60}}));
		games.add(new Game("Invaders", new int[][]{{94,85,75,85,75},{85,96,75,82,75},{85,92,70,79,70}}));
		games.add(new Game("J-Type", new int[][]{{86,65,75,88,80},{78,60,70,87,75},{72,60,70,86,70}}));
		games.add(new Game("Jetp4k", new int[][]{{75,85,75,80,80},{68,90,75,75,70},{76,88,75,85,75}}));
		games.add(new Game("jm00 - a boomshine clone in 4k v1.2", new int[][]{{86,82,80,82,92},{74,90,75,92,85},{72,75,75,88,100}}));
		games.add(new Game("Just Get Bigger 4K", new int[][]{{85,87,80,68,90},{78,95,75,80,85},{90,90,80,90,90}}));
		games.add(new Game("Kart", new int[][]{{80,75,80,82,75},{82,86,80,80,80},{82,82,80,80,75}}));
		games.add(new Game("Keggle", new int[][]{{91,90,80,78,90},{90,95,80,86,90},{82,85,75,89,90}}));
		games.add(new Game("Left 4k Dead", new int[][]{{100,97,80,99,95},{100,95,75,99,95},{97,93,75,100,90}}));
		games.add(new Game("MEG4kMAN", new int[][]{{95,95,75,86,70},{97,98,80,92,70},{95,95,80,92,65}}));
		games.add(new Game("NiGHTS 4k", new int[][]{{90,84,0,85,80},{90,88,0,87,75},{95,87,0,100,80}}));
		games.add(new Game("PacPitfall4k", new int[][]{{65,0,65,81,60},{80,0,60,92,60},{70,0,65,86,55}}));
		games.add(new Game("Pixeloids4k", new int[][]{{92,89,0,91,90},{92,88,0,100,95},{88,82,0,94,75}}));
		games.add(new Game("Putty Shuffle", new int[][]{{93,92,75,97,75},{85,90,75,86,80},{85,94,70,85,70}}));
		games.add(new Game("Q*Bert4K", new int[][]{{80,0,80,82,80},{75,0,75,86,75},{70,0,75,94,85}}));
		games.add(new Game("QuadSquad4k", new int[][]{{55,50,0,65,65},{40,60,0,65,70},{45,45,0,65,65}}));
		games.add(new Game("Red Baron 4K", new int[][]{{85,96,70,98,0},{87,95,75,81,0},{92,100,75,96,0}}));
		games.add(new Game("RevolvoMan-4K", new int[][]{{94,88,80,81,70},{92,92,75,84,70},{92,92,80,74,70}}));
		games.add(new Game("RhythmSphere", new int[][]{{60,73,75,83,75},{75,76,75,89,80},{65,69,70,62,75}}));
		games.add(new Game("Robo rampage", new int[][]{{82,93,75,93,85},{80,92,75,84,75},{82,90,74,96,90}}));
		games.add(new Game("Run Over Zombies", new int[][]{{70,83,70,92,75},{85,90,75,99,75},{85,87,65,95,75}}));
		games.add(new Game("Scr4mble", new int[][]{{55,60,60,52,70},{70,60,65,73,70},{50,60,75,72,70}}));
		games.add(new Game("Sea Spin", new int[][]{{78,76,75,81,75},{78,86,75,77,70},{80,84,70,88,85}}));
		games.add(new Game("Sea through", new int[][]{{45,73,75,78,85},{60,87,75,96,95},{40,40,70,84,80}}));
		games.add(new Game("Space Paranoids 2D4K", new int[][]{{82,86,75,70,80},{90,90,70,87,75},{78,94,75,87,80}}));
		games.add(new Game("Splosh4k", new int[][]{{90,73,75,87,95},{85,70,75,90,90},{82,65,70,96,95}}));
		games.add(new Game("Star 4x", new int[][]{{60,88,0,61,70},{84,93,0,91,75},{60,80,0,85,60}}));
		games.add(new Game("submarin", new int[][]{{40,84,75,66,80},{65,89,70,89,75},{25,95,75,76,85}}));
		games.add(new Game("Super Marble World", new int[][]{{76,70,75,92,75},{85,75,75,90,70},{68,65,70,92,80}}));
		games.add(new Game("Tekicars4k", new int[][]{{79,90,80,79,85},{82,92,75,74,85},{72,88,75,72,80}}));
		games.add(new Game("Treasure4k", new int[][]{{78,70,75,82,70},{72,82,75,72,70},{92,78,70,87,65}}));
		games.add(new Game("Ultimate Tic-Tac-Toe", new int[][]{{75,60,60,50,85},{75,60,70,65,90},{84,60,60,85,85}}));
		games.add(new Game("Virtual On 4k", new int[][]{{50,41,60,68,55},{72,40,70,79,60},{45,35,60,52,50}}));
		games.add(new Game("Word Twister", new int[][]{{56,83,70,84,80},{75,60,60,68,70},{68,74,75,82,80}}));
		games.add(new Game("World Rally Driver 4k", new int[][]{{82,90,60,91,95},{82,93,60,89,95},{84,90,50,86,95}}));

??? Did you get an NPE with Gravitational Fourks or are you confusing me with someone else?

I’m not confusing anything, I wrote and you quoted:

If your game didn’t get a zero for failing with an NPE the comment above doesn’t really apply to it does it?

Kev

My game got two zeros. Versions of Java not specified, but with 1.6.0_12 I get

java.lang.InternalError: 
****************************************************************
ERROR: the javaplugin.version system property wasn't picked up
by the com.sun.deploy.Environment class. This probably happened
because of a change to the initialization order in PluginMain
where the deployment classes are being initialized too early.
This will break jar cache versioning, and possibly other things.
Please undo your recent changes and rethink them.
****************************************************************
	at sun.plugin2.applet.Applet2Environment.initialize(Applet2Environment.java:113)
	at sun.plugin2.applet.viewer.JNLP2Viewer.run(JNLP2Viewer.java:195)
	at sun.plugin2.applet.viewer.JNLP2Viewer.main(JNLP2Viewer.java:63)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
	at java.lang.reflect.Method.invoke(Method.java:597)
	at com.sun.javaws.Launcher.executeApplet(Launcher.java:1388)
	at com.sun.javaws.Launcher.executeMainClass(Launcher.java:1246)
	at com.sun.javaws.Launcher.doLaunchApp(Launcher.java:1066)
	at com.sun.javaws.Launcher.run(Launcher.java:116)
	at java.lang.Thread.run(Thread.java:619)

No mention of any NPEs.

So then my comment wouldn’t apply to your game then. Why quote it? Since the results have now been updated to ignore zero anyway, whats to worry about?

Kev

Wow! Excellent Judging! Very helpful reviews. Big thanks to Appel, Chris, and Demonpants for the great comments! Darkfrog, errr, thanks for playing it! :slight_smile:

Appel, the Java4K Result page looks great! Excellent job!

Congrats to Markus for a well deserved victory. Gloat away!

Congrats Markus! But you really should have left it till the last week to submit, you probably put off a number of potential entrants.

Anyone else think percentage scores are unnecessarily precise given that the scores from each judge differed by over 50% in some cases. I think out of ten scores would probably be better for future contests.