JChip16BR the newest toy

Chip16

The last days I’ve been playing around a new virtual machine. This VM is known as Chip16 and its specification can be obtained from Ngemu. The Chip16 is quite simple, it has only 19 registers (including PC and SP), the CPU speed is only 1Mhz, memory’s size 64 KB (65536 bytes). The main way you to interact with the machine is by mapped io. The set of instruction (at version 0.7) is around 48. It’s a start project for those want to learn a little bit of emulation. Maybe you know its father Chip8 that has some inconsistencies and undocumented features.

Emulator Basic flow

Emulator basic flow
Emulator basic flow

Basic steps:

  • [0] Load ROM -> ROM it’s the input of the machine, sometimes it can be a ISO image or a specific structure created by community. It’s a file (structured or not) that contains the data to be executed and read by the machine.
  • [1] Load Memory -> You need to know the memory map of target system. So you properly fill the memory with data from ROM at the correct addresses.
  • [2] Initiate Machine -> It’s the initial state of the machine, some of them used to start with random data all over the RAM, and it used to have the initial address for the first opcode among other tasks.
  • [3] Decode Opcode -> It’s basically the act of read the opcode from memory (pointed by PC) and its parameters too.
  • [4] Execute Instruction -> With the full set of data, you know how to execute the instruction (using the parameters).
  • [5] Events -> Eventually the machine does some events or some interruptions are raised.
  • [6] Cycle Tasks -> This are the tasks performed at given time (measured by clock (number of cycles) or time (ms)): update screen, update inputs and etc.

JChip16BR

JChip16BR architecture
JChip16BR architecture

I did a simplest implementation using Java as language/platform and Java2D as render engine. The idea is: implement this vm and have fun with object-oriented programming. I’ve divide this into several objects. I tried to apply some design patterns, basic oop and etc. The core is the facade Machine which provide methods for start, pause, resume, see the internal state of CPU, draw and etc. The coolest part (IMHO) is the CPU, full of internal classes composing the instruction table which is findable by opcode. For graphics it used a simple short multidimensional array, acting like a screen of pixels.

Video

Source code

You can access the source code at GitHub.

PS: I used the concepts of emulator, simulator and virtual machine as synonymous but my intend was to show how a vm/emulator/simulator or mix of all this works at implementation level.

TDD in practice – developing a game

Test-Driven Development

On this post I’ll try to explain on practise some concepts and techniques behind the TDD and I’ll do it by example.

Scenario


Product: A role-playing game titled as Breath of Fantasy

Story: The battle scheme – Create the battle scheme for the game.

Description:
The battle will be based on turns, each time a character attacks and the other receives the damage. The character has energy points and power points. These two properties are integers numbers. For example, if the hero(energy points: 60, power points:45) attacks a enemy(energy points: 60, power points:45) the enemy will have the energy decreased some points. The damage received, decreased energy points, by enemy depends on luck factor. Luck factor is a random number from 0 to 100 that is given for each attack turn.

There is four kinds of attacks based on your luck factor:

  1. When the luck is 0-3 then the attack is Miss -> doesn’t cause any damage;
  2. When the luck is 4-70 then the attack is Normal -> causes 1/3 of your power points in damage;
  3. When the luck is 71-96 then the attack is Lucky -> causes 1/3 of your power points plus twenty percent of this 1/3 in damage;
  4. When the luck is 97-100 then the attack is Critical -> causes the double of normal attack.

STEP BY STEP

Write a tests to given story, the first one should validate when a character attacks another with Miss attack and see if the damage caused is 0.

@Test
public void validateMissAttack(){
   UnitCharacter hero = new UnitCharacter("hero",60,45);
   UnitCharacter enemy = new UnitCharacter("enemy",60,45);
   hero.attack(enemy);
   Assert.assertEquals(enemy.getEnergyPoints(), 60);
}

You still don’t have the class UnitCharacter, so you can create it now. You should create it just enough to compile and run the test.

public class UnitCharacter {
 public UnitCharacter(String name, int energy, int power) {
 }
 public void attack(UnitCharacter other) {
 }
 public int getEnergyPoints() {
  return 0;
 }
}

When you try to run the test it will fail; PERFECT this is what we want! Now move to next, write code to that test pass. The most obvious /simple solution should be used:

public int getEnergyPoints() {
  return 60;
}

Run the test again, test pass; PERFECT this is what we want! Now move to next, refactor the code. The constructor of UnitCharacter lets spaces for misinterpretations for example use the second argument as power point instead of energy. To solve this possible problem we could use tiny types.

public UnitCharacter(String name, Energy energy, Power power) {
}

public class Energy {
 public Energy(int energy) {
 }
 public int getEnergyPoints() {
  return 60;
 }
}

public class Power {
 public Power(int power) {
 }
}

Looking the new code, we can imagine that there will be a little change in UnitCharacter. The method getEnergyPoints() will just delegate the calling to Energy. Now we’ve refactored all it just run the test again and see if it passes. Now we can move next: create the next tests.

Given: A hero(energy points: 60, power points:45) and a enemy(energy points: 60, power points:45)

  • Test: when the hero attacks the enemy with Normal attack and see if the damage caused is 15.
  • Test: when the hero attacks the enemy with Lucky attack and see if the damage caused is 18.
  • Test: when the hero attacks the enemy with Critical attack and see if the damage caused is 30.
    @Test
    public void validateNormalAttack(){
        UnitCharacter hero = new UnitCharacter("hero",new Energy(60),new Power(45));
        UnitCharacter enemy = new UnitCharacter("enemy",new Energy(60),new Power(45));
        hero.attack(enemy);
        Assert.assertEquals(enemy.getEnergyPoints(), 45);
    }
    @Test
    public void validateLuckyAttack(){
        UnitCharacter hero = new UnitCharacter("hero",new Energy(60),new Power(45));
        UnitCharacter enemy = new UnitCharacter("enemy",new Energy(60),new Power(45));
        hero.attack(enemy);
        Assert.assertEquals(enemy.getEnergyPoints(), 42);
    }
    @Test
    public void validateCriticalAttack(){
        UnitCharacter hero = new UnitCharacter("hero",new Energy(60),new Power(45));
        UnitCharacter enemy = new UnitCharacter("enemy",new Energy(60),new Power(45));
        hero.attack(enemy);
        Assert.assertEquals(enemy.getEnergyPoints(), 30);
    }

When you try to run all these tests they fail; PERFECT this is what we want! Now move to next, code to these tests pass. I’ll focus on validateNormalAttack method test to make it pass.

public class Power {
    private int power;
    public Power(int power) {
        this.power = power;
    }
    public int getPowerAttack() {
        return power/3;
    }
}

public class Energy {
    private int energy;
    public Energy(int energy){
        this.energy = energy;
    }
    public int getEnergyPoints(){
        return energy;
    }
    public void decrease(int attack) {
        energy -= attack;
    }
}

public class UnitCharacter {
    private final Energy energy;
    private final Power power;
    public UnitCharacter(final String name,final Energy energy,final Power power) {
        this.energy = energy;
        this.power = power;
    }
    public void attack(final UnitCharacter other) {
        other.energy.decrease(power.getPowerAttack());
    }

    public int getEnergyPoints() {
        return energy.getEnergyPoints();
    }
}

When you rerun the tests the validateNormalAttack pass but the test validateMissAttack fails! The test suite help us to know it and now we can code to fix this fail! One important concept is the luck factor which influences the type of attack, let’s try to design the luck to the attack.

public interface Luck {
    double nextAttackLuckFactor();
}

public class LuckAttack implements Luck {
    private final Random random = new Random();
    private final static double MISS = 0;
    private final static double NORMAL = 1;
    private final static double LUCKY = 1.2;
    private final static double CRITICAL = 2;
    @Override
    public double nextAttackLuckFactor(){
        int randomFactor = random.nextInt(101);
        if (randomFactor > 0 & randomFactor <=3){
            return MISS;
        } else if (randomFactor > 3 & randomFactor <= 70){
            return NORMAL;
        } else if (randomFactor > 70 & randomFactor <= 96){
            return LUCKY;
        } else {
            return CRITICAL;
        }
    }
}

public class Power {
    private int power;
    private Luck luck;
    public Power(int power) {
        this.power = power;
        this.luck = new LuckAttack();
    }
    public int getPowerAttack() {
        return (int) ((power / 3) * luck.nextAttackLuckFactor());
    }
}

Now if we rerun the tests sometimes one or two passes sometimes all of them fails. Why? The luck is a random number then is unpredictable. Now we can use mocks / stubs objects (there is a tech discussion about the differences between mock and stub) to simulate the desired luck factor.

public class Power {
    private int power;
    private Luck luck;
    public Power(int power,Luck luck) {
        this.power = power;
        this.luck = luck;
    }
    public int getPowerAttack() {
        return (int) ((power / 3) * luck.nextAttackLuckFactor());
    }
}

public class TestAttack {
    @Test
    public void validateMissAttack(){
        Luck missLuck =  new Luck() {
            @Override
            public double nextAttackLuckFactor() {
                return 0;
            }
        };
        UnitCharacter hero = new UnitCharacter("hero",new Energy(60),new Power(45,missLuck));
        UnitCharacter enemy = new UnitCharacter("enemy",new Energy(60),new Power(45,missLuck));
        hero.attack(enemy);
        Assert.assertEquals(enemy.getEnergyPoints(), 60);
    }
    @Test
    public void validateNormalAttack(){
        Luck normalLuck =  new Luck() {
            @Override
            public double nextAttackLuckFactor() {
                return 1;
            }
        };
        UnitCharacter hero = new UnitCharacter("hero",new Energy(60),new Power(45,normalLuck));
        UnitCharacter enemy = new UnitCharacter("enemy",new Energy(60),new Power(45,normalLuck));
        hero.attack(enemy);
        Assert.assertEquals(enemy.getEnergyPoints(), 45);
    }
    @Test
    public void validateLuckyAttack(){
        Luck luckyLuck =  new Luck() {
            @Override
            public double nextAttackLuckFactor() {
                return 1.2;
            }
        };
        UnitCharacter hero = new UnitCharacter("hero",new Energy(60),new Power(45,luckyLuck));
        UnitCharacter enemy = new UnitCharacter("enemy",new Energy(60),new Power(45,luckyLuck));
        hero.attack(enemy);
        Assert.assertEquals(enemy.getEnergyPoints(), 42);
    }
    @Test
    public void validateCriticalAttack(){
        Luck criticalLuck =  new Luck() {
            @Override
            public double nextAttackLuckFactor() {
                return 2;
            }
        };
        UnitCharacter hero = new UnitCharacter("hero",new Energy(60),new Power(45,criticalLuck));
        UnitCharacter enemy = new UnitCharacter("enemy",new Energy(60),new Power(45,criticalLuck));
        hero.attack(enemy);
        Assert.assertEquals(enemy.getEnergyPoints(), 30);
    }
}

This refactoring made the Power uncoupled of the concrete implementation of Luck this has drive our design to a better state. We could use a mock framework as Mockito, JMock and others to simulate the “falses” results. Now try to rerun the tests. All pass great. Next step refactor the test class there is too much duplicated code. Always try to be DRY

IS JUST IT? NOW THE TESTS ARE OVER…?!

No! for each new class we’ve created we should create unit tests for them. For example:

  • what if I create a Energy or Power passing negative number to it?
  • what if I create a UnitCharacter with null Energy?
  • what if I create a UnitCharacter with energy points equals to 97 and power points equals to 51 how the round will work?

You need to to feel safe and confidence about you code. There is some tools for analysing the coverage of your unit tests (like Cobertura) over the project.

THE BENEFITS

The design was entirely modelled by TDD. Now you have a solid suite of tests and when you would do the design of the spell and item usage you can run this tests again and see if they fails. TDD not only give us safety it also lead us to the appropriate design, we don’t spent too much time thinking in the future, we solve the problem of that story and we prove our solution.

IS THAT THE BEST SOLUTION TO THIS PROBLEM

No! You probably has a better one, this is one of the possible.

Null object pattern

Null pointer
Null pointer

The use of the return to null on a method or function is quite normal when you are programming. (or nil depends on your programing language). There is a pattern called Null Object Pattern that could help you avoid this kind of returning and improve your design for a different state and behavior for the situation where your object is null.

Some days ago I was working on a simple application which read a text file and transforms each line in a command to be executed. So when it finds a line that couldn’t be converted to a valid command the method had returned null.

I have a single method “run” to perform all this commands.

public void run(){
List<Command> allCommands = buildFrom(new File(“actions”));

for (Command command : allCommands){
if (command != null)  command.execute();
}

}

Note that there is a condition check if the command is null or not and then not throw any NullPointerException, I could check the nullability on buildFrom and just return the commands not null. But instead I’ve created a NullCommand that just shows to user what command won’t be perfomed.

public void execute(){
log(“The action “+action+” won’t be perfomed: Invalid action!”);
}

There is an important consideration: the over (and wrong) use of this pattern can lead you to think that errors or bugs are part of the normal flow of program. In my case it was usefull because I show the message for user informing him so he can edit the text file and fix the error (mistyping, grammar, whatever) and then run it again. The next time you think in return null consider the use of this pattern.