Skip to content

feat: Battle City Tank Arena demo — LLM communication paradox#35

Open
JNK234 wants to merge 14 commits into
mainfrom
battle-city-tank-arena
Open

feat: Battle City Tank Arena demo — LLM communication paradox#35
JNK234 wants to merge 14 commits into
mainfrom
battle-city-tank-arena

Conversation

@JNK234

@JNK234 JNK234 commented Mar 18, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Adds Battle City Tank Arena demo replicating BattleAgentBench's finding that inter-agent communication hurts weak LLM models but helps strong ones
  • 3 progressive stages: Solo Navigation → Team Battle → Team + Comms
  • LLM tanks use llm:choose for action selection and llm:chat-with-template for tactical messaging
  • Stateful history accumulation so tanks can learn from failed moves across ticks
  • Rich observations: 7×7 ASCII minimap, lookahead, move-failure feedback, open directions, ally/enemy positions

Stages

Stage What It Tests
1: Solo Navigation Single LLM tank navigates maze to reach flag
2: Team Battle 2 LLM tanks vs 2 scripted bots, implicit cooperation
3: Team + Comms Same as Stage 2 with messaging via comms-override? toggle

Key Design Decisions

  • Collapsed paper's 7 stages into 3 to focus on the communication paradox
  • History accumulates for full run (60-100 ticks) — no periodic clearing
  • generate-message uses fresh context (llm:clear-history) for single-shot message generation
  • Bot AI uses state machine (retreat → attack → chase → patrol)

Test Plan

  • Stage 1: Tank navigates around walls toward flag, shows varied actions
  • Stage 2: Blue LLM tanks engage red bots, score is non-zero
  • Stage 3: Same as Stage 2 with ally messages visible in output
  • Toggle show-observations? to verify move-failure feedback and open directions
  • Toggle show-thinking? to verify reasoning chain output

JNK234 added 14 commits March 17, 2026 18:46
31x31 symmetric arena with brick/steel walls, tank breeds with
cardinal movement, bullet mechanics (2 patches/tick, wall damage),
explosion visuals, scripted bot AI (patrol/chase/attack/retreat),
3 stage setups (solo nav, team battle, team+comms), win conditions,
scoring system, and full interface widgets. LLM action selection is
stubbed with random choices for testing.
Replace random action stub with llm:choose that sends tank
observations (position, minimap, enemies, objectives) and picks
from [move-forward, turn-left, turn-right, fire, stay]. Adds
config.txt (openai/gpt-4o-mini/0.3), llm:load-config in setup,
llm:clear-history per decision, error handling with carefully
block, and LLM call counter.
Stage 3 inter-tank messaging via llm:chat-with-template with
message-template.yaml. Ally messages injected into decision
context via llm:set-history before llm:choose. Speech bubbles
via label/message-timer. show-thinking? toggle uses
llm:chat-with-thinking to expose reasoning chains. Adds
action-template.yaml for thinking mode fallback parsing.
Documents the BattleAgentBench communication paradox hypothesis,
three stages, setup instructions with config placeholder, expected
results per model tier, and all LLM primitives used.
All 31 row strings now verified at exactly 31 characters to
match the 31x31 world grid. Removed unused variable.
Bug 1: lower-case is not a NetLogo 7 primitive. Replace with
multi-case position checks for action parsing.

Bug 2: Map Y-axis was inverted — teams spawned at enemy bases.
Change py = row-idx - 15 to py = 15 - row-idx so Red base (R)
renders at top (y=+15) near red tank spawns (y=+13) and Blue
base (B) at bottom (y=-15) near blue tank spawns (y=-13).
- Plot pens use <pen> with <setup>/<update> children instead of
  inline text content
- Chooser uses <choice type="string" value="..."> instead of
  <option> with quoted text
- Add patchSize/frameRate as floats
- Add plot-level <setup>/<update> elements
- Add pen legend="true" attribute
Remove per-tick llm:clear-history from choose-action so tanks retain
memory across ticks. Remove redundant Stage 3 llm:set-history injection
(ally messages already included in observations).

Add last-move-failed? tracking to execute-action and initialize it in
setup-tank-defaults. Enrich observations with wall-blocked feedback and
open cardinal directions so the LLM can navigate around obstacles.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c55ce67e68

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +343 to +345
ask tanks with [is-llm? and tank-health > 0] [
set my-observation build-observation
]

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Rebuild observations after messages are delivered

In Stage 3, build-observation is cached here before generate-message/deliver-messages run, but choose-action later sends that cached string to llm:choose. Since build-observation only serializes ally-message when it is already present, a message generated on tick N cannot influence the ally's decision until tick N+1. That means the new comms stage is not actually testing same-tick tactical coordination, and the comms-override? toggle will appear much weaker than intended.

Useful? React with 👍 / 👎.

Comment on lines +587 to +591
llm:clear-history
let vars (list
(list "observation" my-observation)
)
let msg llm:chat-with-template "message-template.yaml" vars

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Preserve action history when generating messages

llm:clear-history clears the current agent's persistent history, and both llm:chat-with-template and llm:choose append to that same history in src/main/LLMExtension.scala. Because this runs immediately before choose-action, every Stage 3 tick wipes the tank's accumulated action context and replaces it with the message-generation exchange, so the headline comparison is no longer 'Team Battle vs Team Battle + comms' but a different memory regime entirely.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant