I think we’re ready to draw something. How can we make the drawing more testable? I have a p-baked idea, for small p.

You’ve heard of half-baked ideas? This one is about p=0.15 baked, but I have high hopes. We’ll see how it goes.

First let’s do a bit of “design”, figuring out our initial display ideas. My screen is 1366x1024. I figure we should have a square display, spanning some number of coordinates centered on the robot. Let’s do a little display spike in a new project.

I think I’ll go old school on the display, make it green on black like an old CRT tube. Some fiddling and I get this picture:

The draw code is this:

``````function draw()
local size = 40
local x = 0
local y = 0
background(40, 40, 40)
strokeWidth(2)
stroke(0, 255, 0, 96)
noFill()
--fill(128,150,128)
rectMode(CENTER)
translate(WIDTH/2,HEIGHT/2)
for x = -10,10 do
for y = -10,10 do
rect(x*size,y*size,size,size)
end
end
textMode(CENTER)
fill(0,256,0)
fontSize(30)
text("R",0,0)
end
``````

The stroke is drawn 2 wide, but only 96/256 opacity. One wide wasn’t visible enough. Note that I translated the screen so that 0,0 is at WIDTH/2,HEIGHT/2. I’ve found that using Codea’s `scale` feature and scaling up from single pixel logic like our scan being at 1-5, doesn’t work well, so I’m planning to scale manually.

Anyway, now we have the basic numbers we need for drawing in the game. This was a spike, and I am under great pressure from fanatics to delete the code. OK, I succumb to the pressure. We’ll just pop back into the robot program.

## How Can We Test This?

In the Dungeon program, 300+ articles and counting, I didn’t figure out much if any testing for the display. I’d like to do better here, even though I expect the display code to be rather simple.

My basic plan for the initial game display is to display the grid, centered around the player’s robot, and to display the various things we’ve scanned in cells relative to the player. We can do that pretty readily, because the facts are all recorded in the player’s robot’s Knowledge. We can use a Lens focused on the robot to give us relative coordinates.

I’m thinking that what I’d like to do is display obstacles as solid blocks, and pits as black. Let’s go back to the spike and see if that will look OK.

``````    fill(0)
rect(5*size,5*size,size,size)
fill(0,256,0, 128)
rect(-3*size,2*size,size,size)
``````

And get this:

I tried full green and it was too bright, so I made it half transparent. Looks OK to me for starters.

OK, where were we?

It seems to me that we might be able to do the drawing this way: In one pass over x from -10 to 10, y from -10 to 10, fetch the factAt(x,y) and convert it to a little object, a display packet, containing a fill color, and an optional letter.

Let’s imagine a little object, GridDisplay that does the conversion. And let’s TDD it.

``````        _:test("GridDisplay", function()
local gd = GridDisplay()
_:expect(gd:display(nil).color).is(color(0,256,0,128))
end)
``````

This should drive out the object:

``````1: GridDisplay -- TestGridDisplay:16: attempt to call a nil value (global 'GridDisplay')
``````

And:

``````GridDisplay = class()
``````

And now we fail on `display`:

``````1: GridDisplay -- TestGridDisplay:17: attempt to call a nil value (method 'display')
``````

And we code:

``````function GridDisplay:display(content)

end
``````

Expectation should fail with a nil. Oops not quite:

``````1: GridDisplay -- TestGridDisplay:17: attempt to index a nil value
``````

Return an empty table. I’m going inch by inch just for fun.

``````function GridDisplay:display(content)
return {}
end
``````

Expectation should fail:

``````1: GridDisplay  --
Actual: nil,
Expected: (0, 256, 0, 128)
``````

Fill in the table:

``````function GridDisplay:display(content)
return {color=color(0,256,0,128)}
end
``````

Expect success. Yes. I think we can draw the game now if we care to:

Let’s try it. The base drawing code looks like this:

``````function draw()
background(40)
if CodeaUnit and CodeaUnit_Lock then
_.showTests()
else
background(128)
stroke(0)
fill(0)
end
end
``````

We’ll call a plain function for now:

``````function draw()
background(40)
if CodeaUnit and CodeaUnit_Lock then
_.showTests()
else
drawGame()
end
end
``````

And we’ll need to fill it in:

``````function drawGame()
setUpDrawing()
drawScreen()
end
``````

If I touch the screen after running the tests, this will crash, as the two functions there are not written. So …

``````function setUpDrawing()
background(40,40,40)
rectMode(CENTER)
textMode(CENTER)
translate(WIDTH/2, HEIGHT/2)
stroke(0,256,0,96)
strokeWidth(2)
end

function drawScreen()
local size = 40
noFill()
for x = -10,10 do
for y = -10,10 do
rect(x*size,y*size,size,size)
end
end
end
``````

This just draws the grid ad hoc, and it looks right on the screen. Now we want to draw the real thing.

Let’s try this:

``````function drawScreen()
local size = 40
noFill()
for x = -10,10 do
for y = -10,10 do
local fact = CurrentRobot:factAt(x,y)
local gd = GridDisplay:display(fact)
if gd.color then
fill(color)
else
noFill()
end
end
end
end
``````

Houston, we have a problem. We have no game set up, no world, no robot. I’ve just finessed this here by saying CurrentRobot.

We need to set up the initial situation and do it just once. Let’s modify `touched`:

``````function touched()
if CodeaUnit_Lock then
CurrentRobot = Robot:setUpGame()
CodeaUnit_Lock = false
end
end
``````

Now all should be fine until we touch the screen, at which point we should crash for want of “setUpGame”:

``````Main:22: attempt to call a nil value (method 'setUpGame')
stack traceback:
Main:22: in function 'touched'
``````

Oddly, that happens twice. I’ll ignore that, probably something about multiple touches. We need the method:

``````function Robot:setUpGame()
local world = World:setUpGame()
return Robot("Louie", world)
end
``````

I should state clearly that at this point we are just building a rope bridge across the various chasms. We’ll figure out a solid bridge soon. Now we want to set up a game world:

``````function World:setUpGame()
local world = World(20,20)
world:createObstacle(5,-3,-5,-3)
world:createPit(2,3,-2,4)
return world
end
``````

I’ve put a big obstacle on the left and a pit on the right. I am not sure what to expect when I run this, most likely some random error. This is very experimental.

``````TestRobot:59: attempt to index a nil value (field 'knowledge')
stack traceback:
TestRobot:59: in method 'factAt'
Main:46: in function 'drawScreen'
Main:29: in function 'drawGame'
Main:16: in function 'draw'
``````

Ah. The robot needs to scan or at least start with an empty knowledge. Let’s try scan:

``````function Robot:init(name,aWorld)
self._world = aWorld
self._x, self._y = aWorld:launchRobot(name, self)
self._name = name
self:scan()
end
``````

Try it.

``````Main:49: bad argument #1 to 'fill' (number expected, got function)
stack traceback:
[C]: in function 'fill'
Main:49: in function 'drawScreen'
Main:29: in function 'drawGame'
Main:16: in function 'draw'
``````

Hm. We got rather far along. What’s this?

``````function drawScreen()
local size = 40
noFill()
for x = -10,10 do
for y = -10,10 do
local fact = CurrentRobot:factAt(x,y)
local gd = GridDisplay:display(fact)
if gd.color then
fill(color)
else
noFill()
end
end
end
end
``````

I forgot to fetch the color:

``````                fill(gd.color)
``````

Again. I think I’ll get a grid. I don’t, but it’s because I didn’t display anything yet. … not entirely clever …

``````function drawScreen()
local size = 40
noFill()
for x = -10,10 do
for y = -10,10 do
local fact = CurrentRobot:factAt(x,y)
local gd = GridDisplay:display(fact)
if gd.color then
fill(gd.color)
else
noFill()
end
rect(x*size,y*size,size,size)
end
end
end
``````

Try again. I get a very green grid.

We need to fix the test and code in GridDisplay. We want the default color to be absent (noFill). Let’s add some lines to the test:

``````        _:test("GridDisplay", function()
local gd = GridDisplay()
_:expect(gd:display(nil).color).is(nil)
_:expect(gd:display("O").color).is(color(0,256,0,128))
_:expect(gd:display("P").color).is(color(0))
end)
``````

This will fail the first and third expect.

``````1: GridDisplay  --
Actual: (0, 256, 0, 128),
Expected: nil
1: GridDisplay  --
Actual: (0, 256, 0, 128),
Expected: (0, 0, 0, 255)
``````

OK, we’ll write this out longhand for now:

``````function GridDisplay:display(content)
if content == "O" then
return {color=color(0,256,0,128)}
elseif content == "P" then
return { color=color(0)}
else
return {}
end
end
``````

I think this passes the test. It does. When I touch the screen, I expect good news.

I do not get good news. I get a blank grid. I wonder where that’s happening. Am I getting no facts? Seems it’s the only possibility.

Let’s write a test for that:

## Test setUpGame

In writing the test, I find that I didn’t set up the game as I thought I had. I was putting in the coordinates incorrectly. Let me recast that:

``````function World:setUpGame()
local world = World(20,20)
-- left top right bottom
world:createObstacle(-5,3,-5,-3)
world:createPit(3,2,3,-2)
return world
end
``````

I think that’s a long obstacle at x = -5 and a long pit at x = 3.

Now back to the test, but I can’t resist looking at the picture.

Woot! The picture is good. And we realize we didn’t display the R …

``````function drawScreen()
local size = 40
noFill()
for x = -10,10 do
for y = -10,10 do
local fact = CurrentRobot:factAt(x,y)
if x == 0 and y == 0 then
fact = "R"
end
local gd = GridDisplay:display(fact)
if gd.color then
fill(gd.color)
else
noFill()
end
rect(x*size,y*size,size,size)
end
end
end
``````

And let me extend `display`:

``````        _:test("GridDisplay", function()
local gd = GridDisplay()
_:expect(gd:display(nil).color).is(nil)
_:expect(gd:display("O").color).is(color(0,256,0,128))
_:expect(gd:display("P").color).is(color(0))
_:expect(gd:display("R").color).is(nil)
_:expect(gd:display("R").text).is("R")
end)
``````

The new rule is that robot returns no color, but a text. This will be easy to implement but shows a problem in our display scheme.

``````function GridDisplay:display(content)
if content == "O" then
return {color=color(0,256,0,128)}
elseif content == "P" then
return { color=color(0)}
elseif content == "R" then
return {text="R"}
else
return {}
end
end
``````

Tests should run.

Now to fix the drawing:

``````function drawScreen()
local size = 40
noFill()
for x = -10,10 do
for y = -10,10 do
local fact = CurrentRobot:factAt(x,y)
if x == 0 and y == 0 then
fact = "R"
end
local gd = GridDisplay:display(fact)
if gd.color then
fill(gd.color)
else
noFill()
end
rect(x*size,y*size,size,size)
if gd.text then
fill(0,256,0)
text(gd.text, x*size,y*size)
end
end
end
end
``````

This should display correctly:

Perfect! But I was here to test setUpGame, wasn’t I? Let’s get back to that:

``````        _:test("Set Up Game", function()
local robot = Robot:setUpGame()
_:expect(robot:factAt(-5,0)).is("O")
_:expect(robot:factAt(3,0)).is("P")
end)
``````

Test passes. Let’s commit: Initial display includes obstacle and pit. player robot display faked.

Let’s reflect … and possibly sum up, as we have hit somewhat of a milestone in our walking skeleton.

## Reflection

I think I like the idea of the little display control table that tells the display loop what to draw at each location. By converting the display information to data rather than just asking each thing to draw itself, we open the door to testing what will be displayed rather than checking by eye.

We’ll still have to check to see that it looks right, but if we do most of the changing in the data table, we’ll keep the display code very simple and be able to test drive more of the code.

I think this is a promising idea, and I’m promoting it to about 0.75-baked.

You might be questioning the wisdom of representing map “facts” with nothing more than a letter, and you would be wise to do so. However, so far there has been no behavior associated directly with things in the scan. Perhaps now they might have the ability to return their own display control table. That could be reason enough for an object to be born.

One issue here is that while in our current implementation, we can readily share objects between World and Robot, such as Knowledge, in the “real” game, the only things passing back and forth will be text, intended to be JSON descriptions of some rather simple tables. So while we might build an object into the Robot’s knowledge, we’d base it on a rather simple text message coming back from our scan of the world.

I’m imagining that all that will be hidden inside the perhaps someday to be written communications objects. We’ll see.

With respect to our walking skeleton, we’re nearly there. I’ve proposed that we’ll allow the robot to “move”, showing that it remembers objects that it has scanned. I think we’ll move it with keyboard commands, though I’m not certain of that. Maybe tomorrow. Certainly this week.

### Syntax

Oh. I’m reminded that I have decided that I don’t like the idea of naming member variables with a leading underbar. The reason is that to type “self._foo”, my fourth finger has to type the “l”, then down to the “.”, then immediately up to the “_”, and I find that awkward, irritating, and error-prone. So I’ll be migrating away from that over time. I’m left with the concern that an accessor method can’t have the same name as the member variable, and I don’t like `getX` kinds of accessors.

I suppose we just shouldn’t have accessors.

## Summary

I think we’re good for the day. We have a starting picture for our stakeholders to look at, and it has a certain retro kind of look like they (I) asked for.

And we can actually do some testing of the display logic. That’s a first.

Stakeholder:
I see on my Mac screen that the black square for the pit doesn’t show up very well. Possibly we’ll need to improve our coloring.
Developer: