Over and out – almost!

When Mood Music
2012-04-24 23:43:00 satisfied Finished Symphony – Hybrid

Well, the programming coursework is over apart from the shoutingmarking. We had to demonstrate our programs this afternoon and submit reports on how our programs worked, programming style and problems encountered.

Some of my classmates hadn’t done all of the set tasks or put in in all the required features, while others had non-working programs (e.g. not saving, creatures not moving), so I’m quite pleased that I had (as far as I can tell) done all that was required, the only bug being the Ogre’s intermittent inability to count his enemies when he’s recalled from disk.

On the other hand, one of my classmates had a graphical swamp, on which you could see the ogre and his enemies actually moving. Ah well, I’m pretty sure I’ve passed. My code is here and my report is here. Oh, and the actual problem/task is here.

I’m grateful that we had to write reports: while I was writing I was able to refine my code and improve the UI a lot. (I don’t claim my UI is good, just that it works and isn’t abysmal.)

All that’s left for this term is tomorrow’s web-enabled business wrap-up/feedback lecture. Then I’m free until September. I don’t intend to slob though: my plans include
• learning more about Swing and other Java graphical tools
• beginning to learn Objective C (iOS apps!)
• beginning to learn PHP
• some literature and real-life research into e-democracy
• if possible, learning to weld so I can start on my bike trailer
• lots of cycling and spinning

I’m also helping teach cycling skills to P7 children on Friday mornings for the next 6 weeks.

Do feel free to remind me how the road to hell is paved!

QuankAbcess

When Mood Music
2012-04-23 22:34:00 accomplished Songs Of Love Pt 2 – Roy Harper

For reasons that are too tedious to explain, occasionally I need to run an old version of the DTP application I loathe – hence the title of this post. It needs MacOS10·5, but Iggy runs 10·6 and 10·7.

I had 10·5 on my XServe but that’s horribly noisy when its working and now the power-supply seems to be dying, so he won’t stay alive long enough to finish booting most of the time. I had picked up an old TiBook which will run MacOS9, 10·4 and 10·5. This was OK but a little slow, and the screensharing image on Iggy was fuzzy.

I had read that VirtualBox won’t fly versions of MacOS earlier than 10·6 server or 10·7 client. I’m very pleased to say this in not true. Installation is a little tedious and not perfect – no VB guest additions, scary verbose boot but it can be done quite easily.

  1. Put your 10·5 installer disk in your host intel mac and start up VB.
  2. Create a blank virtual machine, telling VB you’re going to install MacOS Server.
  3. I’d suggest giving your new vm 4GB of RAM.
  4. Create a new HD – at least 20 GB. VDI format seems to work, so stick with it. The same goes for dynamic allocation.
  5. When you first run your new VM, there will be a very verbose and scary-looking startup. Stick with it!
  6. Eventually you will get to the traditional ‘select language’ first screen of MacOS install. Go through the process as normal until you are asked where to install OSX. There will be no available hard disks, even though you created one in step 4.
  7. At this point, choose DiskUtility from the installer menu. You’ll find that no partitions/volumes have been created on the HD you created. So use partition, remembering to set format as GUID in the options pane.
  8. Once the partitioning is done, close DU. This will take you back to the main installer, so install away!
  9. When the installation is finished, shut down your vm and eject the installer disk from your host mac. Otherwise you’ll just be taken through the installation process again.
  10. Reboot your new VM, sit through the verbose boot and lo and behold you’ll get to the normal personalisation screens as if you were installing MacOS on a real mac.
  11. You won’t be able to install VB guest additions, but you’re not left without being able to share stuff between host and guest. InVB, under the devices menu, set your vm to use a ‘bridged adaptor’. Then in the VM, under system prefs, set up sharing as normal. Then your host mac will be able to see the guest and the guest will be able to see the host.

You are stuck with 1024 by 768 screen area but there are speed advantages over the 1GHz TiBook I was using – a 10·5 system running at over 2·5 GHz. I’m very pleased!

 

Completely puzzling

 

When Mood Music
2012-04-21 04:42:00 frustrated Heroes – Roni Size/Reprazent

Having achieved non-trivial, working JUnit tests, I thought I could spend some time improving the UI/UX of my game. Several frustrating hours later, I’m not sure this was a good idea.

Poor UI/UX
The ‘working’ version first asks the user if s/he wants to restart a saved game, and warns him/her that if there isn’t one, a brand-new game will be started. This is presented as a bog-standard yes-no dialog.

On choosing ‘No’, i.e. the user is presented with the first representation of the swamp in a very plain dialog. The user’s only choice is to click ‘OK’ (or force-quit).

Clicking ‘OK’ forces the program to redraw the swamp after the ogre has moved and potentially been joined by an enemy. The user is offered the choice of seeing the creatures move again (by clicking ‘Yes’) or saving the game (by clicking ‘No’). Again. it’s a standard yes-no dialog.

Clicking ‘Yes’ here does make the creatures move as they should. Clicking ‘No’ refreshes the view of the game-state that will be saved. Here’ the user’s only choice is again to click ‘OK’. Doing so terminates the program quietly, cleanly and boringly!

Should the user initially have chosen to restore a saved game, the saved state is displayed, again in a plain dialog with just an ‘OK’ button. Clicking ‘OK’ brings up the yes-no-dialog where the user can carry on moving the creatures.

Road to nowhere
This seemed poor – I wanted to offer the user some kind of menu. It’s easy to create a dialog with text offering numbered choices and a space for the user to type his or her choice. It’s fairly easy to trap invalid numeric input and force the user to re-enter a choice. Alternatively, if the user enters a non-numeric choice, it’s possible to use exceptions to trap this. However, trying to account for users entering random strings of differently incorrect choices led me into a merry hell of nested do-while loops.

So nearly!
Then inspiration struck – while looking for ways of replacing the standard icons in Java dialog boxes, I’d seen a way to ‘doctor’ standard ‘yes-no-cancel’ dialogs with my own text. So I could do away with needing to trap poor user input by offering buttons for ‘I don’t want to play at all’, ‘play a brand-new game’ and ‘restore saved game’. Setting this up took a fairly short time, and so I set about testing whether my better-UI/UX game worked.

The brand-new game worked as it should. Saving and recalling seemed to work, so I set about doing more rigorous testing: starting a game, saving it, recalling it, saving it again, terminating the app, restarting the app, recalling the game…

Hmm – not quite right. In any recalled game, regardless of whether or not the app was terminated and restarted, the ogre intermittently ignores 1 or 2 immediate enemies. Sometimes 2 immediate enemies will kill him, as should happen. Sometimes he kills one of them. If there are three immediate enemies, he may kill one of them or two of them may kill him while the third is ignored. If there are four, the ogre is definitely killed.

Bah encore
So I thought I could go back to the early, ‘working’ version of the game which didn’t have this fault. WRONG! The fault is there – I’d just not tested thoroughly enough at the time! It appears my choice is not ‘working but poor UI’ or ‘intermittently faulty but better UI’. Instead, it’s ‘intermittently faulty but poor UI’ or ‘intermittently faulty but better UI’. So the choice is easier – big hairy wow.

I have to start writing up tomorrow to have time to create a decent report for the end of Tuesday. We also have to demonstrate our programs working on Tuesday afternoon. The lecturer has to see 20 programs and interview their creators in 2 hours. So there’s a chance he might not see the fault. (I’m not relying on this!) I’m wondering whether I should point out the fault and/or mention it in my report.

Weird

When Mood Music
2012-04-20 16:58:00 boggled Shuttin’ The Ole Dirt Down – Rev Hammer

Even though 1 + 1 ≠ 2, the following test passes. (swampSize is set elsewhere to be 4)

public void testDrawSwampMap() {
//Set up
Swamp s1 = new Swamp(swampSize);
String actualMap;
String expectedMap;

//Get value. The swampMap will vary every time the Swamp is created because
//an Ogre is added IN A RANDOM PLACE each time a Swamp is created.
//So remove the ogre, then draw the map.
s1.removeCreature(s1.ogreXcoord(), s1.ogreYcoord(), “OGRE”);
actualMap = s1.drawSwampMap();

expectedMap =
“(0,0): t(1,0): t(2,0): t(3,0): tnn” +
“(0,1): t(1,1): t(2,1): t(3,1): tnn” +
“(0,2): t(1,2): t(2,2): t(3,2): tnn” +
“(0,3): t(1,3): t(2,3): t(3,3): tnn”;

//Test
assertEquals(expectedMap, actualMap);
}

So “=” ≠ “equals”!

1 + 1 ≠ 2

When Mood Music
2012-04-20 16:05:00 annoyed, puzzled In The City – Razorlight

Following on from here, take a look at this code:

package _06Swampless_JUnitTests;

public class testString {

public static void main(String[] args) {
String piece1 = “donkeyOGREsnake”;
String piece2 = “donkeysnake”;
String piece3 = piece1.replace(“OGRE”, “”);
if (piece3 == piece2) {
System.out.println(“yeehah”);
}
System.out.println(“piece1: ” + piece1);
System.out.println(“piece2: ” + piece2);
System.out.println(“piece3: ” + piece3);
} //end main

} //end class

This sets up pieces of text which are identical except the first one has some extra characters, namely “OGRE” . A third piece is created as the first one minus “OGRE”. So the third piece should be the same as the second. The if block will print ‘yeehah’ if this is true and ‘boo hiss’ if they’re not.

The actual output is:
boohiss
piece1: donkeyOGREsnake
piece2: donkeysnake
piece3: donkeysnake

So two identical-looking pieces of text are in fact not identical. Bah!

Need drugs!

 

When Mood Music
2012-04-20 13:31:00 shattered Chinese Rock – The Ramones

I’ve just drunk my first coffee for over 2 years. 90 minutes of intensely watching 11-year-olds cycling – and trying to demonstrate and lead them towards good cycling habits – is utterly draining. And this was in a school play-ground. I’m not really looking forward to taking them out on the road.

Now I’m back to writing JUnit tests…

Testing my head

 

When Mood Music
2012-04-19 15:24:00 puzzled Fiji – K-series

Original thoughts
On the last of the JUnit tests, namely testing writeSwampToDisk(). This is called within the game if the user decides he or she is bored with watching creatures move around and try to kill each other.

The way I’d want to test it is to invoke a game and record the current state, e.g. the current value of Swamp() or drawSwampmap(). Then I’d save the game (which automatically closes it. Then I’d recall the game and compare the recalled state with the previously-noted saved state. If the two are the same, the read and write have succeeded.

The write method is within Swamp(), so that it can be called from Swamp()‘s basic routine. However, the read method is within a separate interface.

(The interface presents the user with a choice of new game or saved game.

  • If the user wants a new game, an new instance of Swamp() is kicked off.
  • If the user wants to recall a game from disk and a saved game exists, the interface’s read method is invoked.
  • [If there isn’t a saved game, the user gets a blocking for not reading the warning previously presented and a new game is started anyway.])

The read method can’t be in Swamp() because this would involve Swamp() trying to read itself. I’d like move the write method fromSwamp() to the interface (partly so I don’t have to write this test but mostly because that would seem neater) but the interface abdicates control to Swamp()‘s basic routine and then exits.

I guess the saved thing could be Swamp()‘s list of creatures, rather than Swamp() itself…… yes, that seems to work.

Some experimentation later
The test didn’t work when I compared lists of creatures. So to make it obvious, I’ve changed to comparing maps – purely textual output. While the two bits of text look identical, the test fails – implying they’re not!

Bah!

Destruction testing

 

When Mood Music
2012-04-18 14:37:00 puzzled Take a Breath (Live) – David Gilmour

Doggedly writing JUnit tests for my Swamp class.

Is there any point in writing a test for a method that randomly returns either ‘true’ or ‘false’? The only test I can think of is that the return value should b done of these values.

Also puzzled how I write a test for my method that draws a map of the Swamp and its Creatures. This will vary each time the game is run because an Ogre is placed in a random position each time the game is run, before the map is ever drawn.

bug-hunt!

When Mood Music
2012-04-17 22:25:00 frustrated The Robots – Kraftwerk

This morning I traced the ‘not working when recalled from saved state’ to the code that that calculates where the ogre is. (This is used to decide whether there should be a battle by counting the number of enemies at the ogre’s location. If there are none, no battle ensues. If there is only 1 enemy, there is a battle which the ogre wins and the enemy is removed. If there is more than 1 enemy, the enemies win, the ogre is removed and the game ends.)

During a brand-new game, the ogre-location method works fine. In a recalled-from-disk game, it doesn’t. The code in question (and rather questionable code) is in two pieces, one for the x-coordinate and one for the y-coordinate. Here’s the x-coordinate code:

public int ogreXcoord() {
    //Declare variable – it needs to be initialised, so use a silly number
    int ogreXCoordinate = 2000;

    //Code
    for (Creature tempCreature : creaturesInSwamp) {
        if (tempCreature.getType() == OGRE ) {
ogreXCoordinate = tempCreature.getxCoord();
} //end if
} //end for-each

    return ogreXCoordinate;
} //end ogreXcoord

The green bits are just comments to help humans read the code. The pink bits are reserved words, i.e words that have special meanings to Java and the blue bit is an example of an instance variable, i.e. a variable that occurs in every instance of the Swamp class.

The code translates as.
This method, named ‘ogreXcoord’ may be called from outside the Swamp class. It will return an integer.
Create an integer variable (which only exists within this method) called ‘ogreXCoordinate’ and sets its value to 2000.
One-by-one, put each Creature in this Swamp’s list of Creatures into a variable called tempCreature.
Then, for each version of tempCreature, if it is an ogre, then set
‘ogreXCoordinate’ to the value of the tempCreature’s x-coordinate.
When you have run through all the creatures and thus definitely have the required xCoordinate, pass this back to the code that called this method.

Why so complex? Only the ogre knows where it is. Each time it moves, it calculates new coordinates for itself and moves to these coordinates. (All Creatures do this, and don’t tell anyone where they are until asked.) So the program doesn’t know where the ogre is until it can ask him. And it can’t ask him where he is until it has found him – and it can only find him by looking through all the creatures in the Swamp and asking them in turn ‘Are you an ogre?’ (I guess this could be shortened by stopping asking once the ogre has been found. And he’s likely to be the first creature in the ‘CreaturesInSwamp’ list because he’s the first creature to be created once the swamp has been created. However, I don’t know that this is guaranteed.)

Anyway, I can show this works when the game is working – the ogreXCoordinate is always right. But in a recalled-from-disk game, this fails – the ogreXCoordinate is always returned as 2000. So the for-each loop is either not working or being ignored.

Bah!!!!!!