Showing posts with label programming. Show all posts
Showing posts with label programming. Show all posts

Saturday, 23 August 2025

10k Rep on Stack Overflow; looking back

After almost 14 years on the Stack Overflow platform, I [finally crossed the 10,000 point reputation threshold](https://stackoverflow.com/users/649048/millhouse) in January 2025. My early days were dominated by Java, moving into Mockito (still by-far my [most popular answer](https://stackoverflow.com/a/7682895/649048), contributing almost a quarter of my total rep!), Spring, then Scala, and into the Play Framework before moving into less-niche territory in the JavaScript/TypeScript world, where the sheer enormity of the user-base made it difficult to be either the first *or* the best at answering anything.
The little "kick-up" around 2021-or-so probably correlates to the widespread uptake of React Hooks, which provided a fairly rich environment of footguns, misunderstandings and head-scratchers as people tried to `useEffect()` their way out of the old `componentDidMount` world. As I'd immersed myself quite deeply into the documentation on "the new way" at the time, and had done a few small greenfield side-projects that used it, it was a pretty fertile period for rep-gathering. Sadly Stack Overflow in 2025 is not what it once was, with a lot of "low-hanging-fruit" (newbie questions, typos, easily-Googleable error messages) being dispensed-with by LLM agent/assistants in a role that they are (and I say this very cautiously) not terrible at. As a result I imagine 10k rep would be very tough going were one to start from scratch today. Nevertheless, as an immense collection of human knowledge and expertise (which I'm sure all the AI scrapers have trained on) it is still remarkable.

Sunday, 28 January 2024

My Apps, 2024

Following a bit of a blogger-trend, here's the stuff I use on the daily. I've omitted things I simply don't use, like custom launchers, podcast listeners, RSS, tracking and/or Mastodon clients; - Mail service: __GMail__ - Tasks: __Drafts in GMail__ - Cloud storage: __Dropbox__ - Web browser: __Chrome__ - Calendar: __Google Calendar__ - Weather: __BOM__ (Melbourne, Australia) app - Video: __Netflix, Disney Plus, Amazon Prime Video__ - Music (Listening): __Spotify__, Spotify via Google Home and/or Chromecast - Music (Creation): __GarageBand__ - Passwords: __1Password__ - Notes: __Drafts in GMail__ - Code: __Visual Studio Code__ - Terminal: __Terminal.app__ - Search: __Google__ This list has shown me how much I depend on Google a) not being evil; and b) not just giving up on a product because they're bored of it ... which concerns me a little. While it still exists though 😉, I *do* highly recommend the use of __Drafts in GMail__ as your general-purpose, cross-platform notes/todo app. You can attach files of arbitrary size, they sync to everything/everywhere *fast* (faster than Dropbox) and it's free (free-r than Dropbox... hmmm 🤔)

Saturday, 30 September 2023

Frenzy.js - the saga of flood-fill

It may surprise you to know that yes, I am back working on Frenzy.js after a multi-year hiatus. It's a bit surreal working on an "old-skool" (pre-hooks) React app but the end is actually in sight. As of September 2023 I have (by my reckoning) about 80% of the game done;

  • Basic geometry (it's all scaled 2x)
  • Levels with increasing numbers of Leptons with increasing speed
  • Reliable collision detection
  • High-score table that persists to a cookie
  • Mostly-reliable calculation of the area to be filled
  • Accurate emulation of the game state, particularly when the game "pauses"

The big-ticket items I still need to complete are:

  • Implement "chasers" on higher levels
  • Fine-tune the filled-area calculation (it still gets it wrong sometimes)
  • Animated flood-fill
  • Player-start, player-death and Lepton-death animations
  • (unsure) Sound.

It all comes flooding back

To remind you (if you were an 80s Acorn kid) or (far more likely) educate you on what I mean by "flood-fill", here's Frenzy doing its thing in an emulator; I've just completed drawing the long vertical line, and now the game is flood-filling the smaller area:

I wanted to replicate this distinctive style of flood-fill exactly in my browser-based version, and it's been quite the labour of love. My first attempt (that actually worked there were many iterations that did not) was so comically slow that I almost gave up on the whole idea. Then I took a concrete pill and decided that if I couldn't get a multiple-GHz multi-cored MONSTER of a machine to replicate a single-cored 2MHz (optimistically) 8-bit grot-box from the early 1980s, I may as well just give up...

The basic concept for this is:

Given a polygonal area A that needs to be flood-filled;

Determine bottom-rightmost inner point P within A.
The "frontier pixels" is now the array [P]
On each game update "tick":
  Expand each of the "frontier pixels" to the N,S,E and W; but
    Discard an expansion if it hits a boundary of A
    Also discard it if the pixel has already been filled
  The new "frontier pixels" is all the undiscarded pixels 
Stop when the "frontier pixels" array is empty
I got this to be pretty efficient using a bit-field "sparse array" to quickly check for already-filled pixels. In the browser, I could perform the per-tick operations in less than 0.1 milliseconds for any size of A. Not too surprising given the entire game area is only 240x180 pixels, and the maximum possible polygonal area could only ever be half that big: 21,600 pixels.

The problem now became efficiently shifting the big pile'o'filled-pixels from the algorithm onto the HTML5 canvas that is the main gameplay area. I'm using the excellent React Konva library as a nice abstraction over the canvas, but the principal problem is that a canvas doesn't expose per-pixel operations in its API, and nor does Konva. The Konva team has done an admirable job making their code as performant as possible, but my first cut (instantiating a pile of tiny 1x1 Rects on each tick) simply couldn't cope once the number of pixels got significant:

This has led me down a quite-interesting rabbit-hole at the intersection of HTML5 Canvas, React, React-Konva, and general "performance" stuff which is familiar-yet-different. There's an interesting benchmark set up for this, and the results are all over the shop depending on browser and platform. Mobile results are predictably terrible but I'm deliberately not targeting them. This was a game for a "desktop" (before we called them that) and it needs keyboard input. I contemplated some kind of gestural control but it's just not good enough I think, so I'd rather omit it.

What I need to do, is find a way to automagically go from a big dumb pile of individual filled pixels into a suitable collection of optimally-shaped polygons, implemented as Konva Lines.

The baseline

In code, what I first naïvely had was:

type Point = [number, number]

// get the latest flood fill result as array of points
const filledPixels:Array<Point> = toPointArray(sparseMap);

// Simplified a little - we use some extra options
// on Rect for performance...
return filledPixels.map((fp) => 
  <Rect x={fp[0]} 
        y={fp[1]}
        width={1}
        height={1}
        lineCap="square"
        fillColor="red"
  />
);

With the above code, the worst-case render time while filling the worst-case shape (a box 120x180px) was 123ms. Unacceptable. What I want is:

// Konva just wants a flat list of x1,y1,x2,y2,x3,y3
type Poly = Array<number>;

// get the latest flood fill result as array of polys
const polys:Array<number> = toOptimalPolyArray(sparseMap);

// far-fewer, much-larger polygons
return polys.map((poly) => 
  <Line points={poly} 
        lineCap="square"
        fillColor="red"
        closed
  />
);

So how the hell do I write toOptimalPolyArray()?

Optimisation step 1: RLE FTW

My Googling for "pixel-to-polygon" and "pixel vectorisation" failed me, so I just went from first principles and tried a Run-Length-Encoding on each line of the area to be filled. As a first cut, this should dramatically reduce the number of Konva objects required. Here's the worst-case render time while filling the worst-case shape (a box 120x180px): 4.4ms

Optimisation step 2: Boxy, but good

I'd consider this to be a kind of half-vectorisation. Each row of the area is optimally vectorised into a line with a start and end point. The next step would be to iterate over the lines, and simply merge lines that are "stacked" directly on top of each other. Given the nature of the shapes being filled is typically highly rectilinear, this felt like it would "win" quite often. Worst-case render time now became: 1.9ms

Optimisation step 3: Know your enemy

I felt there was still one more optimisation possible, and that is to exploit the fact that the game always picks the bottom-right-hand corner in which to start filling. Thus there is a very heavy bias towards the fill at any instant looking something like this:

----------------
|              |
|              |
|             P|
|            LL|
|           LLL|
|          LLLL|
|         LLLLL|
|        LLLLLL|
|       LLLLLLL|
|      LLLLLLLL|
|     LLLLLLLLL|
|    LLLLLLLLLL|
|   LLLLLLLLLLL|
|  LLLLLLLLLLLL|
| LLLLLLLLLLLLL|
|SSSSSSSSSSSSSS|
|SSSSSSSSSSSSSS|
|SSSSSSSSSSSSSS|
----------------
where
  • P is an unoptimised pixel
  • L is a part line, that can be fairly efficiently represented by my "half-vectorisation", and
  • S is an optimal block from the "stacked vectorisation" approach
You can see there are still a large number of lines (the Ls and the P) bogging down the canvas. They all share a common right-hand edge, and then form a perfect right-triangle. I started implementing this change but ended up aborting that code. Worst-case render time is already significantly below the "tick" rate, and the code was getting pretty complex. Okay, it's not optimal optimal, but it's Good Enough. Whew.

Sunday, 27 August 2023

Searching for the next SPA

I've been quite taken with a particular style of casual, "clever" game that rose to prominence during The COVID Years but still has a charm that keeps me visiting almost daily:

  • Wordle (the original, and the "rags to riches" ideal)
  • Quordle (a beautiful initial implementation, albeit reduced now)
  • Heardle (recently escaped from the clutches of Spotify)
and most-recently:

There are a heap of common factors amongst these games (and I'll optimistically include my own Cardle here too) that I think make feel so "nice":

  • Rejection of obvious monetization strategies
  • Feel resolutely mobile-first in UI/UX (large elements, zero scrolling!)
  • Delightful levels of polish (micro-interactions, animation etc)
  • Focused; not just a Single *Page* App, but almost a Single *Pane* App

Of course there's also the little matter of having a great idea with suitably nice mechanics and frequently creativity (Connections I think excels in having creative, challenging content by Wyna Liu that is pitched just *chef's kiss*) but I think there are still areas of the word-association, letter-oriented game landscape to be explored.

For this next one I also will be trying out Svelte after reading the superb "Things you forgot (or never knew) because of React" by Josh Collinsworth which very nicely articulated what feels a little "ick" about React development these days, and paints a very nice picture on what's on the other side of the fence. The scoped-styling and in-built animation abilities in particular seem like a perfect fit for this kind of app.

Now I just need an idea...

Monday, 22 February 2021

Computers I Have Known - Part IIe

Next up in my Computers I Have Known "journey" (ugh) is the classic Apple IIe, in this case the final, "Platinum" edition with 128Kb of RAM, numeric keypad, light grey case, matching monitor and 5.25" floppy drive.
By this time, my family and I had migrated from the UK to Australia, and the Electron, although it had come with us, may as well have been made of cheese. Nobody had heard of it, nobody used it, it was a dead end. My Dad, still working off the "buy what they use at school" advice from before, went completely bananas with a full IIe "educational pack" which bundled in a Star NL-10 9-pin dot matrix printer and a ton of "educational software" (most of which was shareware, but had at least been gathered together and well-organised)

Having a printer was Very Exciting, and considerable amounts of ink were consumed with the classic Print Shop banners being the main culprit. I vividly remember the THINKING ... THINKING ... THINKING ... PRINTING screens that Print Shop displayed while you waited 15, 20 or more minutes for a big banner to tractor-feed its way into the world.


The Apple II was already a bit long-in-the-tooth when we got it around 1989 - it had an amazing run for such an "average" 8-bit machine - no doubt helped by Apple's strategy of getting it into schools. It was certainly quite depressing seeing far cheaper Commodore Amigas in department stores running demos of high-resolution bouncing balls, reflective surfaces and relatively high-fidelity music. The 16-bitters were coming and it was impossible not to be impressed by how far the goalposts had moved on. The flipside for me was the popularity of the Apple with my peers (and the ease of copying its disks) made it far easier to expand my software portfolio than I had ever experienced before.

Some more of my favourite software for the Apple: (all screenshots from Moby Games)

Choplifter

A clever example of how great playability can completely offset some pretty ordinary (tiny, horribly-coloured) graphics. You can play it on the Internet Archive here.

California Games

Radical! Tubular! You're wild and crazy! A nice collection of action sports that didn't take itself too seriously. You can play side 1, which includes my favourite, BMX, at the Internet Archive.

Wings of Fury

What an absolute masterpiece of an arcade game. Amazing playability and balance of realism and challenge. You can actually go and play a version of it online and while it's the PC version not the Apple original, I recommend you go and do so immediately. The Internet Archive also holds the true Apple II version but it asks for side 2 of the disk and I can't find a way to feed that in; although the Emularity project that makes this possible are aware of the issue.

As I progressed through high school, the capabilities of the Apple as a word processor became far more important. Many of my peers were still submitting draft essays in longhand, then rewriting the whole thing again after getting the teacher's feedback - a process that seemed incredibly repetitive and wasteful. I took the opportunity (for perhaps the first time in my life) to harness the power of the computer to save me some effort. AppleWorks had been included in our original bundle of shareware, and I used it for a good few years. Being about as non-WYSIWYG as it gets, it was my introduction to marking up text, and thus some of the fundamental ideas of HTML were getting drip-fed to me as I wrapped a sentence in Ctrl-U (or whatever it was) to underline it. The whole printing process was a lot more manual too - choosing a font and its output quality was done with buttons on the printer's front panel, and constant vigilance was required when spanning pages; top- and bottom- margins were highly variable in reality.

A revelation came along when I "obtained" (probably through some disk-copying skulduggery at school) what I think must have been BeagleWrite (although I have no recollection of that name), which was a full WYSIWYG, GUI-and-mouse driven word processor, with white background and black text making it look like a true Mac refugee. I was fairly familiar with the Mac's point-and-click paradigm but actually doing productive work with it (as opposed to just fooling about on someone else's computer) was pretty incredible. I believe we'd call it "discoverability" now, but the ability to just see what commands were available, and of course undo them was mind-blowing. I think it's fair to say that the reason I became "good with computers" was through amazing pieces of software like BeagleWrite where there was no penalty for just trying stuff to see what happens. Apparently this is not that common a trait ...
BeagleWrite screenshot from Vintage Geek - for such an incredibly-good bit of software there is very little evidence of its existence!

And I can't write a post about the Apple II without mentioning my own brush with its legendary creator Woz. Probably the most famous person I will ever have had the pleasure and honour of meeting.

Saturday, 30 January 2021

Computers I Have Known - Part One

In the spirit of very entertaining blog posts by Jacques Mattheij and Jim Lawless, I thought I might celebrate having written computer software professionally for 20 years, by recapping all the computers I have known, since the beginning.

And in the beginning, there was, an Acorn Electron. Yes, the "King of the 8-Bits" BBC Micro's little brother, and, well, he wasn't very good. In their efforts to reduce the Beeb's chip count and cut costs to a Sinclair Spectrum-rivalling price-point, Acorn bottlenecked the processor's access to memory so that while for the most part it was compatible with BBC BASIC, programs would run, at best, around half the speed of the Model B.

8-year-old me neither knew nor cared about this however; I had a computer, in my bedroom, and it was amazing. I'm pretty sure my Dad picked the computer up from Curry's or Dixons (UK high street electrical retailers) at a heavily discounted price, just in time for my birthday. As he is a complete luddite I'm fairly sure he was advised by a family friend (a teacher) that the BBC Micro (or indeed, something compatible) would be a fine choice; I don't recall ever outwardly expressing a desire for a home computer but had certainly enjoyed playing the BBC B at our friends' house. That machine was very well specced with a disc drive and dedicated colour monitor; my setup was substantially lower-rent with a domestic-grade cassette recorder and a monochrome television pressed into service for display duties. Sadly I don't have a picture of my first "workstation" but here are some very close approximations:
The cassette recorder here is almost identical to what I had, in the same position to the left of the Electron, because that's where the I/O and motor control connectors were and the cable wouldn't reach anywhere else.
Here's the mighty Binatone 12-inch monochrome TV that was my "monitor". I was very pleased to be able to recall that brand name! It plugged into the Electron's RF port and had to be tuned in for a nice sharp picture. Although pretty crappy by almost every measure, I was at least lucky enough to have this TV dedicated for my computing, and so didn't have to share the family TV.

Together with the hardware came a veritable mountain of boxed software; almost all of it from Acornsoft in their distinctively-80s graph-squares-and-neon-script style:
(from acornelectron.co.uk)

These were a couple of my favourites; Starship Command was a very Star Trek-inspired shoot-em-up with lovely smooth circular scrolling and "high" resolution graphics (in black-and-white, the cost of such a resolution), while Sphinx Adventure was an impenetrable (well, it seemed like it) text adventure in the GO NORTH, TAKE SHOVEL, GO EAST, USE SHOVEL style.

Yep, games. Sorry, I'd love to be able to say I was busting out 6502 assembly and "racing the beam", unlocking hidden hardware capabilities and pushing the limits ... but no, while I did program, it was mostly small BASIC experiments based on these two books (that came in the original bundle):
Although I stayed very much "within the lines" of what those books showed me, I still built up the fundamentals of programming; variables, conditionals, looping. I never got as far as arrays on the Electron as far as I can tell - I remember wanting to make a virtual airport departures board (after being suitably impressed by the board at Gatwick Airport I think) and being stumped at how to make the departures "move up" as the topmost flight disappeared.

The main aspect of BBC BASIC I remember being fascinated with was the graphics "API", principally the LINE command, which would draw a straight line between two X,Y points in the current paint colour. Combined with a pair of nested loops, I'd build spider-web like meshes around the edges of the screen. Very, very slowly. The super-smooth inner curves thus achieved delighted me then, and indeed still do:
(Go chortle at my Codesandbox HTML Canvas version here)