Baren81 Devlog

Galaxy16 – When It’s a Tie, the AI Won’t Decide Who Wins

Title card: When it is a tie, the AI will not decide who wins — Galaxy Devlog #16

Written by

in

,

Galaxy Devlog #16 · Read the Galaxy build log

I do not write code and I cannot read it. Call the Cat: Galaxy, the Unity sequel to a game I already shipped, is written line by line by AI agents. My job is to say what I want, set the rules they work under, and check whether what comes back is actually right.

This one is about a run that should have counted as a win and ended as a loss instead.

In a time attack, I collected everything and still lost

Our game has a mode where you collect every piece of food on screen within a time limit. But when the moment you eat the last piece of food and the moment the timer hits zero land in the exact same frame, the result gets processed as a loss. To the player, everything was clearly eaten — and the screen still says “Failed.”

There’s no syntax error in the code. Eat it while time remains: success. Time runs out before you finish: failure. Both of those worked exactly right. The problem was that nobody had ever decided which one goes first when the two events happen in exactly the same frame.

Why does the AI miss this spot?

Ask an AI to “fix the time attack judgment,” and it looks only at the timer code.

The logic that sends you to failure once the timer passes zero is correct on its own. The logic that records a collected item into the list is also correct on its own. Looked at separately, there’s nothing to fix. So the AI says “this looks fine,” and it doesn’t get flagged in code review either.

What’s missing isn’t code — it’s a specification. Nowhere did anyone write the sentence: “if the last collection and the time-out happen in the same frame, which one gets processed first?” When it’s not in the spec, the AI fills that gap arbitrarily. And an arbitrary fill usually lands against the player.

The direction we actually fixed it in: the collection that came in during that frame gets applied first, and only then is the timer checked. So on a tie, “complete” wins — because the player already ate it on screen.

Clearing a list while looping through it

The same day’s log has a second one. Inside the very function that eats the last target, the code was also clearing out every other piece of food still on screen.

Looping through the food that had been touched while also clearing that same list mid-loop pushed the next index out of the list’s range. This one doesn’t show up in ordinary play either — it only appears when the last item and several others get processed in the same frame, at once.

Clearing a list mid-loop pushes the next index out of range.
Clearing a list mid-loop pushes the next index out of range.

The fix is simple: finish looping through everything that was touched, then clean up exactly once. The list doesn’t get touched while the loop is still running.

Deciding priority for overlapping events ahead of time

Both bugs share the same root cause: two events can land in the same frame (or the same tick), and nobody decided which one wins.

So while fixing this, we started keeping a table that writes down, ahead of time, which side wins for each kind of overlapping event. Here’s the format.

Two events overlapping in the same frameWinnerWhy
Last goal collected · time limit hits 0Collection (complete)player already ate it on screen
Player hit · invincibility startsInvincibility firstso the same hit doesn’t land twice
Player dies · stage clearsClearmeeting the goal takes priority
Item pickup · stage endsPickup firstto avoid dropping the reward

The priority table format for events that overlap in the same frame.
The priority table format for events that overlap in the same frame.

Only the first row is something we actually decided and put into code this time — the other three rows are only there to show how the table gets filled in. Those aren’t situations we’ve hit in our own game yet, so don’t read them as the right answer; the point is finding the spots where overlap can happen in your own game and filling them in yourself.

When handing this to an AI, add this one line:

“Can this event overlap with another event in the same frame? If it can, which rule in the priority table applies? If it’s not in the table, ask before writing the code.”

And add one more habit: don’t remove elements from a list while you’re looping through that same list. If something needs to be removed, collect it separately and clean it up once, after the loop ends.

What this post comes down to

Code compiling and working correctly in most playthroughs doesn’t mean that code is right. Which side wins when two events land at the exact same instant is a rule a person has to decide first — not something the code decides — and an AI will fill that gap arbitrarily if the rule doesn’t exist.

Both of these fixes are done as far as static checking goes, but whether the same-frame collision actually reproduces in play still needs to be confirmed in Play Mode. Which is why writing down the spots where events can overlap, ahead of time, beats fixing them one at a time as they show up.

Worth reading together

Even with priorities decided, two agents editing the same file at the same time can overwrite that very table. How we kept the two agents from erasing each other’s changes is covered in the two posts linked below.

→ Galaxy01 – I Gave Two AIs Separate Folders

→ Galaxy07 – The AI Is Not Allowed to Stage Every File It Changed

Solo dev of Call the Cat, shipped after 178 days
on Google Play
and Steam.
Now building the sequel, Call the Cat: Galaxy, in public.