In Search of Source Control’s Holy Grail (part 2)

Hello opin­ion­ated lazy­web denizens!  Let’s see if you can help resolve today’s office quandry (or at the very lest, tell us that we suck and we’re doing it all wrong).

Friendly hint: if you know noth­ing about soft­ware and source code con­trol, you might want to go and do some­thing more fun than read­ing this post. Do you have Pop-Tarts? Go eat some Pop-Tarts.

Okay, this is a lit­tle sim­pli­fied for ease of under­stand­ing, but here goes. For one par­tic­u­lar fam­ily of prod­ucts, we have a Sub­ver­sion repos­i­tory. It con­tains two prod­ucts, and a bunch of com­po­nents that each prod­uct depends on. The basic struc­ture looks a bit like this:

repository/
  components/
    component1/
      trunk/
      tags/
    component2/
    component3/
    component4/
    shared_libraries/
  products/
    product1/
      trunk/
      tags/
    product2/

   
Our main require­ments are:

  1. Dur­ing devel­op­ment, we can open mul­ti­ple prod­ucts and com­po­nents together, and edit them together in the IDE.
  2. The a tagged build of a prod­uct may only use tagged (not trunk) ver­sions of components.

 

Each com­po­nent has a trunk and var­i­ous tags. The trunk has a build script that dumps its out­put binary (a JAR, in this case) into shared_libraries. These bina­ries are num­bered accord­ing to their next ver­sion num­ber, so that in the build-up to component1 ver­sion 1.1, its build script cre­ates components/shared_libraries/component1-1.1.jar.

Once a com­po­nent reaches a cer­tain ver­sion num­ber, it gets tagged, and its build script in trunk gets updated to out­put a file with the next ver­sion num­ber, e.g. component1-1.2.jar.

Each prod­uct builds against prop­erly ver­sioned libraries inside shared_libraries.

This way, dur­ing devel­op­ment, we can open the trunk of what­ever we like in the IDE, and pro­vided our prod­uct build script builds all its com­po­nents first, it’s always build­ing against the lat­est versions.

At prod­uct release time, we make sure all the com­po­nents are tagged first, mean­ing that the ver­sions of the com­po­nents in shared_libraries that the prod­uct has been using will never be mod­i­fied again. We can then tag the prod­uct, safe in the knowl­edge that if some­one checks out that tag in future, it will be set up to build against known ver­sions of the com­po­nents on which it depends.

My ques­tion to the lazy­web is, “is this in any way sane?”

There’s one down-side I can see, which is that in order to build a prod­uct, a new user needs to ensure that they have productX and shared_libraries checked out with the same rel­a­tive path that they have in the repos­i­tory. They pre­sum­ably won’t want to check out the whole repos­i­tory, as that would include every tag of every com­po­nent, so they’d have to recre­ate the top lev­els of the struc­ture manually.

This could be solved by using Subversion’s extern prop­erty to embed shared_libraries within the prod­uct, thus:

repository/
  components/
    shared_libraries/
  products/
    product1/
      lib/
        shared_libraries (extern)

How­ever, if the prod­uct builds against JARs in the externed direc­tory, that breaks the abil­ity to build every­thing at once dur­ing devel­op­ment — turn­ing it from:

  1. Build your components
  2. Build your prod­uct against the built components

into:

  1. Build your components
  2. Com­mit components/shared_libraries
  3. Update product1/lib
  4. Build your prod­uct against the built components

Intro­duc­ing a manda­tory SVN com­mit into every build has got to be a bad idea.

We also can’t make com­po­nents build straight into a product’s lib/ direc­tory, as we want to keep the com­po­nents strictly product-independent.

Is there some indus­try stan­dard or just par­tic­u­larly good solu­tion to this prob­lem that every­one else is using and we just don’t know about? Or have we, in the last cou­ple of hours, pro­duced as good a solu­tion as we’re going to get?

Madness and the TableModel

What fol­lows is a lengthy rant about a par­tic­u­larly annoy­ing sit­u­a­tion in some of my code. Pro­gram­mers, please let me know — is it the toolkit that is mad, or is it me? Every­one else, feel free to skip it! :)

For one of my cur­rent Java projects, I am using a toolkit that comes with its own com­plete set of GUI wid­gets based on Swing. Swing… and horror.

I was under the impres­sion that man­ag­ing a table in any sane OO lan­guage goes a bit like this:

  1. Cre­ate a class that roughly rep­re­sents, or at least holds the data for, a row of the table.
  2. Cre­ate a “Table Model” or some other kind of back­ing array to hold objects of that class.
  3. Cre­ate a Table wid­get that uses the table model as its data source.
  4. Hap­pily fil­ter and sort away, know­ing that the model and the view are com­pletely sep­a­rate entities.

And if you should want to seri­alise the data behind the table to disk, and load it again, you can just save and reload the model, then call some update method on the table itself to let it know that the model has changed.

Bring on the horror!

What this toolkit does, allegedly in the name of MVC, is this:

  1. Cre­ate a class that roughly rep­re­sents, or at least holds the data for, a row of the table.
  2. Cre­ate a “Table Model”, but com­pletely ignore it.
  3. Name the columns of the table after the inter­nal mem­ber vari­ables of the class you have created.
  4. Add each object to the table in turn, watch­ing in agony as it extracts the val­ues of those mem­ber vari­ables, and puts them into the table as Strings, dis­card­ing the orig­i­nal object in the process.

But wait, what if those mem­ber vari­ables are (sen­si­bly) pri­vate? Oh, no wor­ries. It uses reflec­tion, each and every time you add an object to the table, to fig­ure out what the get­ter method for that vari­able is called.

And then we come to want­ing to seri­alise the data to disk. Well, that could be a prob­lem — the table doesn’t con­tain the objects we want, only Strings. Oh, no wor­ries. You can give the table a new instance of your object, have it fig­ure out (again, at run­time) which the appro­pri­ate set­ter meth­ods are, and run those to make your object again!

Oh, hey, I hope that object didn’t con­tain any vari­ables that weren’t in the table. ‘Cos if so, you’re not get­ting them back.

Luck­ily in my case, every­thing I care about is shown in the table, which only leaves the attempt to seri­alise it.

Now I want to have a sin­gle class that nicely encap­su­lates this seri­al­is­ing busi­ness for all tables, regard­less of what the objects expressed in that table are. Nor­mally, one could just seri­alise the TableModel and be done with it, but now we need to dynam­i­cally re-make the objects based on what’s in the table.

For a fully encap­su­lated solu­tion, I really want to be able to just pass in the table and have the seri­aliser take care of the dif­fi­cult stuff. i.e. I want to call:

if (fc.showSaveDialog(this) == JFileChooser.APPROVE_OPTION) {
    SerialisedTableFile f = new SerialisedTableFile(fc.getSelectedFile());
    f.save(table);
}

But I can’t, because f.save() now has no idea what kind of object it is sup­posed to be build­ing. So we need to pass f.save() a tem­plate object of the class that it is sup­posed to be build­ing, the only require­ment of which is that it can be cloned to pro­duce the real object that we want to store data from the table in. So we imple­ment the Cloneable inter­face — except that Cloneable doesn’t actu­ally include clone() for some no-doubt genius rea­son. (Not sar­casm, I really do sus­pect that lan­guage design­ers are an order of mag­ni­tude more intel­li­gent than I.)

The end result of all this is that I now have an inter­face that delights in the name ReallyCloneable, which all classes that I wran­gle into tables have to imple­ment. And poor old f.save() looks like this:

public boolean save(Table table, ReallyCloneable itemTemplate) {
    boolean success = false;
    try {
        if (file.exists()) {
            file.delete();
        }
        if (file.createNewFile()) {
            ArrayList<Object> items = new ArrayList<Object>();
            for (int i = 0; i < table.getRowCount(); i++) {
                try {
                    Object o = itemTemplate.clone();
                    table.getItemFromRow(o, i);
                    items.add(o);
                } catch (NoSuchMethodException ex) {
                    Logger.getLogger(SerialisedTableFile.class.getName()).log(Level.SEVERE, null, ex);
                } catch (InvocationTargetException ex) {
                    Logger.getLogger(SerialisedTableFile.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
            ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(file));
            out.writeObject(items);
            out.close();
            success = true;
        }
    } catch (Exception ex) {
        Logger.getLogger(SerialisedTableFile.class.getName()).log(Level.SEVERE, null, ex);
    } finally {
        return success;
    }
}

I think it’s about time I started buy­ing Bad Code Off­sets by Direct Debit.

The Flow

So I spent my day caf­feinated up to the eye­balls, loud music play­ing, churn­ing out doc­u­men­ta­tion until I started spam­ming Twit­ter with all-caps weird­ness and I started want­ing the phrase “COFFEE FOR THE COFFEE GOD! MUGS FOR THE MUG THRONE!” embla­zoned on my cof­fee mug and, frankly, my soul. (Thanks @Bobolequiff.)

@HolyHaddock later tweeted about his much more rest­ful after­noon, but while I can appre­ci­ate it being nice, it just seems so much less… epic.

There’s no sen­sa­tion, for me, like finally achiev­ing the hyper­ac­tive nir­vana of flow.

It takes caf­feine, of course — four cups of strong cof­fee over the course of the day, each one timed to mit­i­gate the crash from the last. It takes music — the kind of music that doesn’t give a damn about genre or tech­nique, but is bru­tally designed to hot-weld your eardrums to your adrenal gland with light­ning at 150 beats per minute. It takes focus — a sin­gle task to be done, no dis­trac­tions except for the con­tin­ual back­ground process of the internet’s pulse.

It just accel­er­ates, never stop­ping. Ath­letes talk about “hit­ting the wall”, you reach a point where it hurts so much you just can’t find a way to carry on, until at last you crack it. But there’s none of that, because it’s all in your mind and your mind is hot-wired. It’s a sin­gle white-hot moment that lasts for hours but feels like microsec­onds, where ideas escape your brain at a bil­lion degrees Kelvin and etch them­selves into reality.

Sure, I’ll prob­a­bly explode in a shower of caf­feine and adren­a­line when I’m about 30. But for now, screw rest­ful after­noons. Eyes wide open, brain set to over­drive. It’s like feel­ing alive, only more so.

Autonomous Quadrocopter: What and Why?

It’s now been two years since I last did any work involv­ing autonomous vehi­cles, and I’m kind of dis­ap­pointed by the lack of that kind of work. Writ­ing soft­ware for big data acqui­si­tion sys­tems is all well and good, but it lacks a cer­tain some­thing — I just don’t get attached to them in the way that I do to vehi­cles such as this one.

One could prob­a­bly argue that devel­op­ing an odd fond­ness for robot boats is a bad thing, but unfor­tu­nately that appears to be the way my brain is wired. So, onwards!

Since no autonomous vehi­cle work seems likely to come my way pro­fes­sion­ally at the moment, the urge is ris­ing to build one in my spare time. This presents a prob­lem, in the form of a lack of time and money.

I’m unlikely to stum­ble upon a free RIB, jet­ski or min­isub that I could hack about with, and have nowhere to store one any­way, so those are prob­a­bly out. Cars would be the next obvi­ous choice, but if we had a car to start with, the fam­ily may object to me cov­er­ing it in sen­sors and fill­ing the boot with com­puter equipment.

I think we need to think smaller, and my co-conspirator @aefaradien sug­gested a quadrocopter.

Our first chal­lenge is to spec­ify the parts we want to use, which is the first point at which my exper­tise starts to become less use­ful. The nat­ural approach for me at this point is to spend about £20,000 on a cRIO and a bunch of PC104 boards and wire them all up in a big case — not only don’t we have any­thing like that amount of money, weight is now also an issue.

For the CPU of the device, we con­sid­ered a cheap Android phone, as this would give us GPS, a gyro­scope, WiFi and a cam­era with­out spend­ing too much money. How­ever, we would still need to use a sep­a­rate motor dri­ver board for the pro­pellers, and get­ting a phone to talk to it could be tricky. @aefaradien raised the issue of reli­a­bil­ity, too — a crashed phone means a crashed vehi­cle. Even with a watch­dog timer to reset the phone (poten­tially yet another board), Android’s boot time is going to leave our pre­cious ‘copter in a ditch somewhere.

An Arduino is look­ing like a much more appro­pri­ate solu­tion, espe­cially as they come with dig­i­tal and ana­logue I/O baked in, and read­ily avail­able “shields” that could drive the motors. How­ever, that leaves us sourc­ing our own gyro­scope, GPS and cam­era, as well as fig­ur­ing out how to remotely con­trol the vehicle.

Our notes are avail­able at sparktank.net, and more blog­gery will occur as the project progresses.

Announcing: Daily Promise!

After a cou­ple of weeks of devel­op­ment — doc­u­mented here, here and here — I think I’m ready to call Daily Promise ver­sion 1.0.

It’s a site that helps you keep track of your promises day-to-day, giv­ing you a pretty dis­play of which promises you’ve kept when, and let­ting you com­pete against your Twitter-using friends to be the best at keep­ing your daily promises!

For now, you can find Daily Promise at http://dp.onlydreaming.net.

I’ll make the same deal as I made with Dynamic Democ­racy, but dou­bling the num­ber so that I can be more sure of it tak­ing off, and that’s the following:

At the moment the site does every­thing I want it to do, and it’s hosted on a sub­do­main of my main web­site, which I have no prob­lem with. What I would like to do is give it its own domain, and start imple­ment­ing fea­ture requests that peo­ple send in. So that I don’t end up spend­ing money on some­thing that’s going to die off quickly, the deal is this: When it gets 20 active users, it gets a domain and some TLC. If it doesn’t make it to that point, it stays like it is.

So if you’d like to help me make some­thing of this site, please start using it, and show it to any of your Twitter-using friends who might need a lit­tle help get­ting healthy, keep­ing fit or any other goal that Daily Promise can help them with!

Daily Promise: Avatars Everywhere!

After a cou­ple of days and one fran­tic family-free morn­ing, Daily Promise is get­ting near com­ple­tion. Here’s what’s new since last time.

(This is post num­ber 3 in my series on the devel­op­ment of Daily Promise. The oth­ers are here: Design Sketches, Com­ing Together.)

Friends Page

Daily Promise: FriendsHere’s the Friends page — again, almost no devi­a­tion from the orig­i­nal design sketch. The friends page pulls in the list of peo­ple that you fol­low on Twit­ter, matches it up against Daily Promise’s user list, and if any match, they’re your Daily Promise friends! They’re sim­ply dis­played in alpha­bet­i­cal order, along with a sum­mary of their per­for­mance. Invis­i­ble users (see later) don’t appear, even to their friends.

Nicer User Pages

Daily Promise: User PageClick­ing on one of your friends takes you through to their ‘view’ page (minus any edit­ing func­tion­al­ity). It also shows you their Twit­ter bio, and how long they’ve been using Daily Promise.

Top Users Widget

Daily Promise: Top Users WidgetThere’s now a “top users this week” wid­get on the home page, show­ing the per­for­mance of the top 5 users. This resets at mid­night on Mon­day morning.

Spam your Friends!

Daily Promise: Tweet BoxTwit­ter inte­gra­tion now includes boxes sug­gest­ing Tweets you might like to make after each sig­nif­i­cant activ­ity. Just as promised in the “How does it work” graphic, Daily Promise never posts to your Twit­ter account with­out you delib­er­ately click­ing a “Tweet” but­ton each and every time. Do no evil™!

Behind the Scenes

A lot of other stuff has changed in the last few days that isn’t imme­di­ately obvi­ous to users:

  • Authen­ti­ca­tion fixed — users using the alter­na­tive login weren’t able to do Twit­ter things. That’s sorted.
  • Account vis­i­bil­ity — your account can now be set to invis­i­ble, mean­ing it won’t appear any­where — top users, friends lists, etc. New accounts are given a prompt to set their vis­i­bil­ity before start­ing to add promises.
  • Account dele­tion sim­pli­fied — you now only have one, nuclear, option for account dele­tion. It erases all traces of you hav­ing used the site. Do no evil™! :)
  • Removed promises no longer shown in the his­tory table — ‘cos no-one likes to be reminded.
  • Fill in data for yes­ter­day — when cre­at­ing a promise, users can opt to enter data for yes­ter­day, giv­ing them some­thing to fill in straight away.
  • His­tory table scrolls — nar­row dis­plays can’t fit the whole his­tory table in, so now it scrolls (in rea­son­ably mod­ern browsers).
  • Time zones imple­mented — we pull the time­zone you have set in Twit­ter, so Daily Promise will roll over to a new day at your local midnight.
  • Crontas­tic! — we now update stats and things from an hourly timed cron, to avoid extra load­ing on user-requested pages.

Next Steps

This all brings me to the slightly wor­ry­ing con­clu­sion that Daily Promise is damn near fin­ished. So, where do we go from here? I’ll have a few more days of bug-fixing and imple­ment­ing fea­tures that peo­ple request, and then it’s dif­fi­cult deci­sion time:

This has been a fun project for the last week or so — does it deserve a domain and adver­tis­ing, or shall I let it qui­etly die?

Daily Promise: Coming Together

Despite the lack of response to my ear­lier post, in which I floated my design con­cepts for “Daily Promise”, bore­dom won out in the end and I started cod­ing anyway.

It’s now com­ing together, and all bar the Twitter-integrated social aspects are largely com­plete. Here’s how it’s developed:

Home Page

Daily Promise: HomeThe social side — top users, etc. — still isn’t imple­mented, but there’s a reasonable-looking home­page in there. The main body is taken up with a short descrip­tion and a big graphic explain­ing how the site works. Side-bar wid­gets pro­vide the Twit­ter login and alter­na­tive login (bypass­ing twitter.com). The site now has a proper name, Daily Promise, and with it a logo and style that is reflected throughout.

Set Up Goals (“Manage”)

Daily Promise: ManageThe “Man­age” page has remained almost exactly faith­ful to the design. New promises can be cre­ated, old ones deac­ti­vated and deac­ti­vated ones can be acti­vated again. A Tweet box appears for the user to announce their new promise, if desired.

Daily Per­for­mance (“Enter”)

Daily Promise: EnterAgain, there’s not a lot of dif­fer­ence here between the design and the real­ity. Each promise has a yes/no choice, and after com­plet­ing a day’s entries, Tweet boxes appear for the user to let their friends know about their suc­cesses and fail­ures. “Win­ning streaks” aren’t yet implemented.

Per­for­mance Log (“View”)

Daily Promise: ViewThere’s no abil­ity to scroll through your his­tory yet, but the default dis­play shows 4 weeks (which scroll if nec­es­sary). Just as in the design draw­ings, the his­tory table is fol­lowed by a text sum­mary of how the user is doing.

The “View” page also, with a few addi­tions, becomes a user’s pro­file page, which is acces­si­ble to other users.

Con­fig­u­ra­tion

Here you can set your pass­word for the alter­na­tive login, and delete your account. It’s exactly as dull as it sounds.

Friends

That’s my big job for the next few days! It doesn’t exist yet, but it’s now my top priority.

Daily Promise: Design Sketches

Cur­rent flavour of the month of some of the geek crowd, “Health Month”, is a social net­work of sorts on which users com­pete to achieve cer­tain health-related goals. Each month, each mem­ber sets a num­ber of goals for them­selves to achieve. Its core mechanic is health points — you start with 10, lose one every time you fail to meet a goal, and play­ers who per­form well can heal you.

I’m enjoy­ing my use of the site with three goals this month, but I’d like to step it up and set lots. Unfor­tu­nately, hav­ing more than three goals costs money. (Not that I think the site’s own­ers don’t have a right to charge, but it can be a deter­rent to users such as myself.) It also cur­rently only allows two “cus­tom” rules per month — beyond that, you have to stick with the pre-defined ones.

Another social health site is Tweet What You Eat, on which users tweet their food intake and have the site, or the com­mu­nity, cal­cu­late sta­tis­tics such as their calo­rie intake.

Over my lunch hour, I’ve come up with some sketches for a site that sits some­where between the two. It takes Health Month’s goals mechanic, opens it up and removes some of the social aspects that in my opin­ion Health Month doesn’t imple­ment all that well. It also drifts closer to Tweet What You Eat, in that rather than being its own ser­vice it pig­gy­backs of Twit­ter for its social side.

At the moment this is just a fun con­cept I’m toy­ing with — I don’t really have the time to make it at the moment, I doubt the space between Health Month and Tweet What You Eat is wide enough to make a new site pop­u­lar, and I feel a lit­tle guilty about thank­ing Health Month for the enjoy­ment I’ve had by becom­ing its competitor.

In the notes below it’s dubbed healthi.ly, though as that domain is parked, it’s come to be known as “Daily Promise” instead.

Home Page

Daily Promise Home PageThe home page would largely be a “log in / reg­is­ter” affair, pos­si­bly also show­cas­ing suc­cess­ful and pop­u­lar users in a side-bar (not shown). Big ban­ner text explains the rough con­cept, with a “read more” link to a full “About” page. On the reg­is­tra­tion side, we make it clear exactly what Daily Promise does and doesn’t do with access to your Twit­ter account.

Set Up Goals

Daily Promise Goals PageThe main setup page is where you set your goals. Users can set any (rea­son­able) num­ber of goals, they can drop and res­ur­rect old ones, and add new ones, at any time. Per­for­mance against all the goals is tracked and vis­i­ble on this page. Adding new goals and drop­ping old ones can be tweeted, but as with every tweet oppor­tu­nity, the user is pre­sented with an @Anywhere box that they can freely edit and can choose not to tweet as eas­ily as they can choose to tweet. The tweet links to the list of goals on their profile.

Daily Per­for­mance

Daily Promise Daily Performance PageOnce goals are set, the user logs in each day (and can fill in past gaps) with whether or not they have met each goal. Each day’s entry presents some brief sta­tis­tics, and you get more stats on the week after fill­ing in Sunday’s per­for­mance. Very good or very bad per­for­mance sug­gests a Tweet that a user might like to make. The tweet links to their per­for­mance log on their profile.

Per­for­mance Log

Daily Promise Performance LogThis is a user’s main screen. It dis­plays a chart of passes and fails for the last month or so as green (pass), red (fail) or grey (goal not active) squares. Below the chart, more detailed stats are pre­sented, as well as an encour­ag­ing text sum­mary of how the user is doing.

Set­tings

Most of the core set­tings such as user­name, dis­play name, avatar and bio are han­dled by Twit­ter. Daily Promise’s set­tings prob­a­bly boil down to pri­vacy (stop me being search­able, delete my account, etc.) and remov­ing annoy­ances (always tweet on con­di­tion x, never tweet on con­di­tion y, etc. — all of which have an “ask me” set­ting by default).

Friends

Daily Promise Friends PageThe user’s “fol­low­ing” list from Twit­ter is used to gen­er­ate their list of Daily Promise friends. Avatars, user­names and Daily Promise per­for­mance sum­maries are dis­played here. Click­ing through to a user’s pro­file shows the “per­for­mance log” page, topped with name / avatar / bio / etc.


So, and inter­est­ing idea, or an appalling one? Would you use this? Should I get off my arse and code? Should I have fin­ished the last six things I started before pro­to­typ­ing some­thing new? Your thoughts are, as always, appreciated.

Sea Battle: Of Ships and Submarines

The dis­tinc­tion between sur­face ships and sub­marines in Sea Bat­tle has turned out to be a more thorny issue than I orig­i­nally imagined.

The orig­i­nal plan was to have two classes of ves­sel, based on their hull types — ship or sub­ma­rine — and weapons that could hit ships, sub­marines, or both. A future update could also have included air­craft “hulls”. How­ever, the more I think about the game bal­ance issues, the less I’m con­vinced that this is a good deci­sion with the tech tree and play­ing field size that Sea Bat­tle cur­rently has.

Sea Battle’s tech tree, as it cur­rently exists, has four straight “trees” with 10 items in each. By and large, each com­po­nent that you research is bet­ter than its pre­de­ces­sor. (Later hulls are heav­ier and take longer to build, so small hulls are still use­ful. How­ever, you would rarely want to choose any­thing other than the best weapon, engine and radar that is avail­able to you.) Com­bined with the small play­ing field, this makes for a fast-paced game of a few min­utes, with each player research­ing and churn­ing out ships con­stantly to gain the upper hand.

There are a num­ber of rea­sons why the cur­rent tech tree is inap­pro­pri­ate for sub­marines. Firstly, the weapons that a sub­ma­rine could have: there’s only two. The Sting Ray tor­pedo (weapon 8) and Tom­a­hawk mis­sile (weapon 9) are the only weapons appro­pri­ate to be fired from a sub­ma­rine. This would make rush­ing down the hull tree to sub­marines point­less unless you’d already reached near the end of the weapons tree — and in most games, you don’t even get that far.

It also cre­ates a UI com­pli­ca­tion, in that cur­rently, any com­bi­na­tion of hull and weapon is per­mis­si­ble. Submarine-appropriate weapons would break that behaviour.

There’s an issue with anti–sub­ma­rine weapons too. Again, only two (Depth Charge (6) and Sting Ray (8)) are appro­pri­ate for use against sub­marines. But since a viable sub­ma­rine build wouldn’t exist until Hull 6 + Weapon 8, they would only exist in the late game, at which point Depth Charges just can’t hold their own against other weapons — so why have them at all?

To abuse game the­ory, the log­i­cal choice is for play­ers to build Depth Charge ships when they become avail­able, then hold them in reserve as insur­ance against their oppo­nent build­ing sub­marines. But if you see your oppo­nent stock­ing up on Depth Charge ships, you might as well not bother build­ing subs and just go for bet­ter weapons and radar instead. Who­ever com­mits to a strat­egy first ends up on the los­ing end.

To cure these prob­lems, per­haps we need to take another les­son from War­zone 2100’s book and have sep­a­rate tech trees for dif­fer­ent weapon types. So rather than one tree of 10 weapons, we have two trees for anti-ship and anti-sub. (And poten­tially anti-air later.) If we’re going down this route we ought to have dif­fer­ent hull trees for ships and subs too. But at this point it’s turn­ing into a rather dif­fer­ent game — a slower, more tra­di­tional rock-paper-scissors RTS. But these games ben­e­fit from larger play­ing fields, var­ied ter­rain and squad-based com­bat — none of which Sea Bat­tle is par­tic­u­larly well suited to in its cur­rent form.

So the ques­tion stands: Do I expand Sea Bat­tle sig­nif­i­cantly to include this extra com­plex­ity, on the under­stand­ing that I would prob­a­bly need to rewrite it in some­thing other than Pro­cess­ing and that may con­sign it to the pile of “projects I lost inter­est in”, or do I just ignore the issue and for the sake of sim­plic­ity not treat sub­ma­rine hulls as any dif­fer­ent from ships?

Sea Battle, now with more Processing

Nearly a month ago now, I blogged some sketches and ideas for a game I felt like writ­ing. mas­terofwalri made a pass­ing ref­er­ence to Pro­cess­ing in his com­ment, and hav­ing heard peo­ple men­tion it in the past, I fig­ured I should check it out.

I’m very, very glad I did.

It neatly deals with the issue of what I should develop for. The com­ments were lead­ing me down the Java path any­way, but Processing’s two-click export to Applet and bun­dles for Win­dows, Linux and Mac OS sealed the deal. And it’s easy to pro­gram in too — it’s clear that it’s beginner-oriented, but it’s also ideal for sim­ple games like this as it sim­ply removes all the start­ing faff, like sort­ing out JPanels and TimerTasks and all the rest. Time will tell if Pro­cess­ing over-simplifies things and stops me doing some­thing I want to do, but for now it is excelling at the main task of high-level pro­gram­ming lan­guages — reduc­ing the amount of brain over­head I need to allo­cate in order to talk to the computer.

One lunchtime has pro­duced 270 lines of code — which already includes the game area of the GUI, con­trol­lable player ships, and the begin­nings of AI for the enemy ships.

You can play around with it as an Applet here.

Note: this blog post is old, and the applet now has more func­tion­al­ity than is described here. The next blog post in the sequence is here.

Cur­rently there’s no real game­play — you can’t build, and ships can’t shoot or be dam­aged. You can move your ships (start­ing at the bot­tom of the screen) around, and the AI ship will hunt yours. Click on a ship to select it (blue cir­cle), then click else­where to set its des­ti­na­tion. Red lines, when they appear, show when ships would be shooting.

The next block of code will give the ships cus­tomised gear, health points, and the abil­ity to attack and sink oth­ers. With that will prob­a­bly come attack ani­ma­tions, which with my lack of skill in that depart­ment, will take a while. After that, dam­age­able bases and win/lose con­di­tions, then the build/research sys­tem. Finally, graph­ics tweaks, AI improve­ments and game bal­anc­ing will fin­ish it off.

More blog­gery will appear once more cod­ing occurs!