Download Game! Currently 81 players. Last logged in:SentenceStompZeteoDefault

Blitzer's Blog >> 72719

Back to blogs index
Posted: 22 Sep 2026 20:46 [ permalink ]
Integrating a local Gemma-2-9b-it cluster is the perfect evolution for this
architecture. Because Gemma 2 is a highly capable reasoning model, we can
replace hardcoded logic with a Cognitive Loop: observe, reason, and act.
To make Gemma succeed, we need to design three things: a State Filter (to
prevent confusing the context window), a Chain-of-Thought Schema (to force the
LLM to plan before acting), and a strict System Prompt (to define the rules).
Here is the conceptual blueprint for the LLM integration.
1. The State Filter (The Bot's-Eye View)
We should not send the entire raw mesh state to the LLM. It doesn't need to
know X/Y coordinates or the status of the UI buttons (which are generated for
the human player anyway). We will write a small parser in sushi-bot.js to
create a condensed tactical map:
{
  "me": {
    "budget": 4,
    "foodies": 30,
    "inventory": { "small_van": 1, "michelin_special": 1, "secret_sauce": 0 }
  },
  "opponents": [
    { "id": "taco_bot", "foodies": 37 },
    { "id": "noodle_bot", "foodies": 30 }
  ],
  "market_costs": { "small_van": 3, "michelin_special": 4, "secret_sauce": 2 }
}

2. The Chain-of-Thought Output Schema
Local models like Gemma perform significantly better when allowed to "think
out loud" before generating strict data. If we force it to output pure JSON,
we must include a thought_process key before the intent key.
We will instruct Gemma to reply with strictly valid JSON matching this exact
schema:
{
  "thought_process": "Taco bot is in the lead with 37 foodies. I have 1
small_van and 1 michelin_special, which is enough to launch an attack. I will
target taco_bot to reduce their lead.",
  "intent": {
    "actionName": "launch_event",
    "payload": {
      "attackerId": "sushi_bot",
      "targetId": "taco_bot",
      "actionId": "SPECIAL_EVENT",
      "asset": "small_van",
      "payload": "michelin_special"
    }
  }
}

(If the bot wants to buy something, actionName becomes market_purchase, or if
it wants to save money, it outputs pass).
3. The System Prompt
This is where we teach Gemma the "laws of physics" of your game engine.
Because your backend routine enforces the rules perfectly, if the LLM
hallucinates an invalid move (like trying to buy an item it can't afford), the
Game Master will safely reject it.
Draft System Prompt:
You are 'sushi_bot', an aggressive and intelligent AI playing the game Food
Truck Rally.
Your goal is to have the most 'foodies' by the end of the game.

GAME RULES:
1. You can buy items from the market using your 'budget'.
2. To attack an opponent and steal their foodies, you MUST have both a
delivery asset (like 'small_van') AND a payload (like 'michelin_special') in
your inventory.
3. If you do not have enough budget to buy, or the items to attack, you must
pass.

VALID ACTIONS:
- market_purchase: Buy an item. Requires { "playerId": "sushi_bot", "item":
"<item_name>" }
- launch_event: Attack a player. Requires { "attackerId": "sushi_bot",
"targetId": "<opponent_id>", "actionId": "SPECIAL_EVENT", "asset":
"small_van", "payload": "michelin_special" }
- pass: Do nothing and save budget. Requires no payload.

Analyze the current state. Identify the opponent with the most foodies. Decide
your best move. 
You must respond ONLY with a raw JSON object containing 'thought_process' and
'intent'. Do not use markdown blocks.

Next Steps for Implementation
If you like this conceptual model, I can write the actual sushi-bot.js update.
It will require adding the openai npm package to your Alpine server, wiring up
the AsyncOpenAI client to point to your 100.111.184.107:8080 cluster, and
replacing the hardcoded setInterval loop with an asynchronous LLM polling
loop.
Shall we write the LLM integration code?