Codea Game – 5

It’s time to work a bit on the “model” for the game. I envision an array of “stories”, each able to answer how long it will take to do it, and how valuable it is. The answers to these questions will get more complex as we grow the game. They’ll depend on team skill, on team practices, and on inherent properties of the stories themselves. We’ll work out those details as we go: that’s how we do incremental development.

For now, a story will have duration and value, and we want to graph the growth of value of the project over time. In terms of what we have so far, we want to convert our array of stories to a Polyline. This decision may not hold forever. I can imagine some more complex relationship between stories and the graph, and if we need one, we’ll find that out and deal with it. For now, we’ll convert an array of stories to a Polyline.

This will really need a test, many tests in fact. We don’t have a unit testing framework yet. There are some available for Lua, and I’m not going to use one. Instead, I’m going to see what we need and grow it. I think that will let us make smoother progress on stories, and we’ll learn more as well. What’s not to like?

Begin with a test:

-- Story testing

function setup()
    testAccess()
end

function testAccess()
    local story = Story(10,2)
    assertEquals(10, story:getValue(),"value should be 10")
end

function assertEquals(expected, actual, message) 
    if (expected ~= actual) then
        print(message)
    end
end

This seems to be a decent start. We’ll call our test from setup, it will create a Story and test whether it has a value, and tests that fail will print their message. To make this fail, we need Story:

Story = class()

function Story:init(value, time)
    self.value = value
end

function Story:getValue()
    return 0
end

Sure enough, this prints “value should be 10″ in Codea’s output window.

We can already see issues that will arise. It’s tempting to build a framework to resolve them, but we’re not that kind of people. But we can think about them a bit.

As it stands, every time we write a test, we’ll have to call it. We will forget, and we will think that test works. We will at least have to really bear down on making each new test fail before it works. And soon, we’ll want a way to collect them up automatically.

We will want tests to tell us what the result was, not that it just failed. That one is likely to become irritating quite quickly, but we’ll wait at least for the first time. Codea does have a string library that should help us when the time comes.

We will want test suites, associated with general ideas or specific classes. We will want not to pollute the global namespace with our assertions. We will want a way to reference in our assertions in all the classes that use them. And so on and on and on.

What we’re gonna do is continue to build our application, with tests as we need them, and build up our tools as we go. We may have to back and fill a bit, but my bet is that mostly we’ll go forward smoothly.

Anyway we have learned a bit about how to test things with this little experiment. Now to our problem, which is something about converting an array of Stories into a Polyline. Array of Stories? What’s that? We can’t put behavior on an array, that would be bad. And what do we call an ordered collection of Stories in Scrum? A Backlog. We need to build and test a backlog. For now, we’ll work in this same little app, just writing a new test against Backlog.

No. We need too much other stuff. Instead, we’ll work in our original little app, and move the tests and such into it. This should also speed the day when we feel the pain of our too rudimentary test tool, since we’ll have system function and testing glommed together.

Confession time. While glomming things together, and thinking about how a Backlog might return a Polyline, I realized that the current Polyline accepts a variable length argument list of points to graph. It seems to me that programs that use Polyline will not be able to do that, since they won’t know in advance how many items to out in the call. I thought of two solutions. One was to put an addPoint method into Polyline, so programs could create an empty one and then add to it. I don’t like that, because I like to create objects in one bang, not build them up. The other idea was to create Polyline with a single array, containing all the points. This seemed better. The thing is, I went ahead and did it. This is pure speculative design change, and I try never to do that. We’ll see if it bites me.

Anyway, what we have now is a project with the mains mushed together, and the new version of Polyline:

-- Game Spike

function setup()
    testAccess()
    testEmptyBacklogHasEmptyPolyline()
    
    frame = Frame(50, 100, 400, 300)
    local poly1 = Polyline({{0,0}, {75,100}, {400,300}})
    poly1:setColor(0,255,0)
    local poly2 = Polyline({{0,0}, {75,75}, {400,250}})
    poly2:setColor(255,0,0)
    frame:addDrawable(poly1,poly2)
end

function draw()
    background(40, 40, 50)
    strokeWidth(5)
    frame:draw()
end

function testEmptyBacklogHasEmptyPolyline()
    assertEquals(2,1,"two does not equal one")
end

function testAccess()
    local story = Story(10,2)
    assertEquals(10, story:getValue(),"value should be 10")
end

function assertEquals(expected, actual, message) 
    if (expected ~= actual) then
        print(message)
    end
end

Polyline = class()

function Polyline:init(...)
    self.polyline = arg[1]
end

function Polyline:setColor(red,green,blue)
    self.red = red
    self.green = green
    self.blue = blue
end

function Polyline:draw()
    pushStyle()
    stroke(self.red,self.green,self.blue,255)
    local p = self.polyline
    for i = 2, #p do
        local start, finish = p[i-1], p[i]
        line(start[1], start[2], finish[1], finish[2])
    end
    popStyle()
end

Next step is to fill in a real first test for Backlog. I decided to start by seeing whether Codea know how to compare tables for equality. Not surprisingly, it does not. Here’s my test:

function testEmptyBacklogHasEmptyPolyline()
    local t1 = {{1,2},{2,3}}
    local t2 = {{1,2},{2,3}}
    local t3 = {{4,2},{2,3}}
    assertEquals(t1,t1,"these were identical")
    assertEquals(t1,t2,"these were equal")
    assertEquals(t1,t3,"these were really unequal")
end

We would hope that the first two would pass and the third fail. But no, the first passes and the last two fail. Codea tests table equality using identity. This leaves us staring our nascent framework in the face. We will have to beef up assertEquals somehow. A clever thing to do would be to look and see what smarter people than I have done, but I’m here to discover and learn. Here’s my cunning plan. I will define a new method, perhaps isEqual, which objects are supposed to implement. I will define its bottom level implementation as just ==, and things that want to do better will override. I’m not entirely sure how to do that in Codea but will implement a global function and start from there. I do not plan to put isEqual directly onto the table, however. Somewhere I learned that adding methods to base classes isn’t the best thing. Instead, I plan to add it to Polyline. Along the way I’ll tweak my test accordingly. Let’s give it a go.

Did you say “that’s not gonna work” at that last paragraph? Well, you should have. Sort of. I did a little googling for things like Lua override == and found out that Lua is ready for this. That’s no surprise. The surprise was that I found it before trying it on my own. What you do if you want custom equality testing is to implement __eq in your class. Like this:

function Polyline.__eq(p1,p2)
    local a1 = p1.polyline
    local a2 = p2.polyline
    for i,p in ipairs(a1) do
        if (p[1] ~= a2[i][1]) then return false end
        if (p[2] ~= a2[i][2]) then return false end
    end
    return true
end

This does the job nicely. My second two tests fail, as expected. But to pass, they should say assertNotEqual. I’ll change them, and implement that assertion:

function testEmptyBacklogHasEmptyPolyline()
    local t1 = Polyline({{1,2},{2,3}})
    local t2 = Polyline({{1,2},{2,3}})
    local t3 = Polyline({{99,2},{2,3}})
    local t4 = Polyline({{1,2},{2,99}})
    assertEquals(t1,t1,"these were identical")
    assertEquals(t1,t2,"these were equal")
    assertNotEqual(t1,t3,"these were really unequal")
    assertNotEqual(t1,t4,"these were really unequal")
end

function assertNotEquals(expected, actual, message) 
    if (expected == actual) then
        print(message)
    end
end

function assertNotEqual(expected, actual, message) 
    assertNotEquals(expected, actual, message)
end

With this change, the tests all run. So with a few lines of code, we have enough of a testing framework to do what we need right now, and we are well on the way to understanding how to make it better. We do know that we’ll need more. Right now the tests are in the Main. They will want to be moved to classes of their own, and we will want some way for our testing code to find them all and run them. We’ll quickly learn that we forget to run them when we have to enter them manually into the list. Maybe we’ll build the introspection code to do that before we get bitten by a missing test. Maybe we’ll have to get bitten. I’d rather not get bitten, but I’m willing to take a bite from time to time, in aid of learning. I will say it is so that you can learn with me, but the truth is, I am making all these mistakes honestly. You get to watch me screw up. Fun, huh?

Is this legitimate XP / Scrum / Agile?

Hold on, you may be saying? Aren’t we supposed to have a working product increment in every Sprint? You’re five articles in and this still isn’t a game. What’s up with that.

Steady. What takes the time is writing down everything we would be talking about if you were sitting here in Brighton. There’s only two or three hours of programming here, as you can tell by the very few lines of code. We’re cycling between product stuff, like the graph and the Story object, and infrastructure, like the Polyline (maybe) and the baby testing framework. Next time, I think we’ll build some collections of stories and calculate value growth from them. We will do that with TDD style tests, and we’ll graph the results. Will that be one session, or two? I really don’t know. I feel optimistic, but it depends on how long it takes to get these words written. I could just code it, and the write it up, it I want you to see what really happens when I do this stuff, not what I tell you, all cleaned up and pretty.

I’m reminded of the how to draw an owl picture. It’s not suitable for work, so I’ll leave it to you to find it on the Web. Anyway, in these articles, I want to show you all the steps between ovals and owl.

See you next time!

Recent Articles

XProgNew – today’s problem

With Bill Tozier, I’m working on re-basing XProgramming.com from WordPress to Ruby/Sinatra etc. We tweeted a bit about an issue we ran into today. It goes like this:

The image we had of the new site is that each article …