First some grumbling, then an idea for something useful that I’ve not done before.

Grumbling

The team has as yet been unable to provide a repo that can be cloned onto my machine and built. With the help of some friends, notably including Luis Soares, I have a rudimentary gradle setup on my machine that will at least build. To make it build, among other things, I had to back up to some random JDK of version 16.

I am certain that whoever built gradle was much smarter than I am, and I suppose that they had in mind that it wold be of benefit to someone. Since lots of people use it, and assuming facts about the market that are not in evidence, it must be useful to a lot of people. It is emphatically not useful to me. It consists of a useless series of incantations that, should I chance to get them right, lets my Kotlin program of two files and about 30 lines compile and run its tests. Since so far I have spent at least a working day of my time on it (real human working day, not a Ron working day), the payoff from gradle is, let me just put it as gently as I can, yet to be attained.

While I am truly certain that this thing must be doing some good for someone, and that it is apparently quite good at what it does, if set up just so, my own reaction to gradle, so far, is best expressed as something that should happen to it and to the horse it rode in on.

Thank you for listening. I hope you chose a nice cheese to go with my whine. Let’s talk about my plan for the next few days.

I have, in a non-gradle, non libGDX, Kotlin, TornadoFX kind of way, a program that shows a tiny bucket circling center screen, and a large bucket somewhere down toward the bottom. I think it’s pretty obvious what this is a metaphor for, namely some kind of Bucket Space game where the little bucket flies around shooting at the big buckets, while they try to capture it or crash into it. You saw that immediately, I assume.

My normal practice with similar games has been to work with the game on screen, and much of the programming has been—let me put it right out there—pretty ad hoc, fiddling the numbers until the game on screen looked good. Those games, written up here somewhere, have turned out rather nicely, but they have not been paragons of test-driven development. I have said, repeatedly, that I don’t know how to test a graphical program when so much depends on what we see on the screen.

Therefore, since I can’t even run the team’s probably-chosen graphics library, I propose to develop this game, at least for a while, without graphics, using TDD and whatever other technology is available to me. I expect this to be … amusing.

Let’s plan.

The Game …

Just because I want to do it this way, I am imagining that we can fly the small bucket by turning it with the arrow keys on the keyboard, and make it accelerate by pressing the upward (forward) arrow. If we give it a gun, we’ll fire it, I don’t know, maybe with the space bar. Furthermore, because it will be interesting, I propose that in the center of the screen there will be a star of great mass, such that the ships> bucket will be attracted and can even orbit the star if you get the speeds and distances just right.

And I propose to implement this with no implementation the graphics, or at least as little reference to the graphics as I can manage.

The Thinking

To do this will require some thinking, and arguably better thinking than I often use in these situations. Let’s see what we can think.

  • I would guess that at maximum speed, it should take a few seconds for the ship bucket to fly across the screen. Let’s say 4. I imagine an orbit of diameter around 1/4 to 1/2 screen width will be common, and of course if you get too close to the sun, you’ll spiral in and, presumably, soon need a new bucket.

  • Space will be the conventional toroidal shape, such that when you fly off at the right you come back on the left, and so on. Space will have some width and height, and since we’re not doing graphics, those values will not be in pixels but in some sensible space measure. I don’t know, light-minutes perhaps. Arbitrary, no doubt.

  • Gravity will act in the conventional way of applying an acceleration to the bucket, and will be subject to the usual inverse square effect so common in our part of the universe. If you’re twice as far away, gravity will be 1/4 what it was when you weren’t twice as far away. Um well, you get the idea, I’m sure.

  • The ship, dammit bucket has a rocket engine of unknown make, such that it applies some amount of acceleration in the direction the bucket is pointed. And there will be some maximum speed, analogous to the speed of light, but without all that shrinkage and mass increase and so on. The bucket’s mass will be considered to be trivial compared to the star, that is, the star is not attracted to the bucket, just the bucket to the star.

The Orientation

I will try to use IDEA’s powers as much as I can, allowing it to create things for me, to refactor things, and so on. Part of my mission, here in Bucket Space, will be to learn things about Kotlin and IDEA.

As such, if you know anything at all about IDEA or Kotlin, you can expect a lot of laughs while I do ignorant things. that will be because I am ignorant in this system. I will not have to feign mistakes. I’ll be making real ones.

Let’s get started.

Some Doing

I will set out to TDD a Bucket class, which will embody the physics of being a Bucket in Bucket Space. We’ll see what else we need as we go on. I’m going to do it all in my existing repo, because it works and setting up another one seems tedious. So there are some odd things in there, like Knowledge and its tests. We’ll pay no attention to those.

I want to begin with a test for the Bucket, that will drive out the Bucket class.

I click to create a new Kotlin Class/File, name it BucketTest.kt, and make it look like this:

package org.geepawhill.starter

import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Test

class BucketTest {

    @Test
    fun bucketExists() {
        val b = Bucket()
        assertThat(b.name).isEqualTo("bucket")
    }
}

When I run the tests I am informed that there is no Bucket. This is not a surprise. IDEA offers to create the class, and does so up in the area where the other real classes are. Seems OK for now. The class is empty, so I expect now to get a problem on the name thing. Which, in the test, I really intended to be a method. That’s OK, we can make it a val. Run the test to see what IDEA and Kotlin think.

Kotlin: Unresolved reference: name

I have some getting used to to do here, but this is as good an error as any, so I can implement name:

class Bucket {
    val name = "bucket"
}

After some messing about with another broken test, left over from whatever I was doing a few days ago, my tests all run green. We are under way. We need another test. One that makes a bit of sense would be nice this time.

I think that our Space Bucket (perhaps a better class name is appearing) probably has a position, and a velocity. Both of these will have x and y coordinates in them. It might be wise to drive out those little classes. (There are perhaps useful classes for vectors and points in Java / Kotlin. For now at least, I Just Don’t Care.)

I’m not going to try to do perfect design right out of the box here. I’m not good enough to do that anyway, and I’m certainly not good enough to do it in Kotlin. So I’ll just posit various objects and we’ll see what we get. the Bucket should be created at a location.

EXPLETIVE me, Java has every useful word defined. Position, Location. Am I allowed to create my own? I hope so.

IDEA seems insistent on using someone else’s definition of Position. I decide to call mine Coordinates, which is at least not taken yet. My test is now:

    @Test
    fun bucketExists() {
        val startingPos = Coordinates(100.0,200.0)
        val b = Bucket(startingPos)
        assertThat(b.x).isEqualTo(100.0)
    }

I think there is a clever way to forward the x property to the Coordinates, and I plan to figure it out, so that you can say .x to a Bucket and get its x coordinate. Meanwhile …

class Coordinates(x: Double, y: Double)

This should make the test fail not liking b.x, and in fact that won’t even compile.

I can’t quite work out how to do the delegation thing that I had in mind, so to get off the dime, I change the test:

    @Test
    fun bucketExists() {
        val startingPos = Coordinates(100.0,200.0)
        val b = Bucket(startingPos)
        assertThat(b.getX()).isEqualTo(100.0)
    }

And …

class Bucket(coords: Coordinates) {
    var coords = coords
    fun getX(): Double {
        return coords.x
    }
}

I also had to do this:

class Coordinates(public var x: Double, public var y: Double)

I declared the parameters public var and was able to get the test to compile and run. Clearly I have some learning to do about Kotlin classes and constructors.

Anyway the test runs, and I can certainly do y like x. Done. Green.

IDEA’s idea of helping seems weak. When I ask it to create a method for getY, here’s what it does:

    fun <E> getY(): Double {
        TODO("Not yet implemented")
    }

And if one attempts to run …

Kotlin: Not enough information to infer type variable E

Well, I honestly have no idea what the <E> even is. Removing it seems to work. More reading to do.

That’ll be enough for now, it is Sunday and nearing brekkers.