Thanks to visit codestin.com
Credit goes to github.com

Skip to content

UgliOrange: fix reward/termination handling (revives #168) - #203

Open
borgr wants to merge 6 commits into
TextArena:mainfrom
borgr:ugli_orange
Open

borgr wants to merge 6 commits into
TextArena:mainfrom
borgr:ugli_orange

Conversation

@borgr

@borgr borgr commented Aug 9, 2026

Copy link
Copy Markdown
Collaborator

Revives @cstorm125's UgliOrange negotiation environment from #168 (branch ugli_orange), with fixes so the reward and termination logic is sound. The env, README, tests, and registration are all @cstorm125's original work; this PR carries them forward plus a small correctness pass. Opened as a fresh PR because the original author's branch is no longer being updated.

UgliOrange is a 3-player LLM-judge negotiation game (P0 Roland / rinds, P1 Jones / juice, P2 Judge) modelling the classic win-win case: both players can meet their objectives from the same 3000 oranges.

What changed

  • Wire the declared error_allowance into the state. __init__ declared error_allowance=3 but reset() never passed it to FFAMultiPlayerState, so it had no effect.
  • Terminate on an exhausted error allowance. step() returned a hard-coded False (never done) on an invalid move. It now returns the real self.state.done, so a player who keeps sending invalid moves can no longer stall the game forever — matching the repo-wide invalid-move convention.
  • Forfeit-to-opponent helper. Added _invalid(): a single invalid move is retried, but once the allowance is exhausted the offender forfeits to the opponent. The two accept-time validation sites (no proposals / accepting your own proposal) route through it.
  • Removed dead code. _process_judge_decision set self.rewards = {...} after each verdict, but rewards flow through state.set_winners() / close(); those env-object writes were never read. Removed with no behavior change.

Verification

  • Author's 11 tests pass unchanged.
  • Added a deterministic driver covering: no-deal-after-max-rounds → draw {0:0,1:0,2:0}; repeated invalid accepts → offender -1, opponent +1; and all four judge verdicts (Roland-only, Jones-only, Both, Neither) plus an over-budget deal correctly scoring as Neither.

Verification gap: the judge is an LLM at runtime. The reward paths were exercised with canned judge decisions (as in the author's own tests); the natural-language judging itself was not driven by a live model here.

Credit: @cstorm125 (#168).

cstorm125 and others added 6 commits August 23, 2025 13:59
…luation

- Implement classic 2-player Ugli Orange case study for negotiation training
- Features Roland/Jones as competing negotiators, LLM judge for evaluation (technically total 3 players)
- Simplified accept logic (latest proposal only) for better LLM compatibility
- Comprehensive judge evaluation with structured 6-field format
- Complete test suite with 11 passing tests
- Comprehensive README with usage examples
# Conflicts:
#	textarena/envs/__init__.py
- Wire the declared error_allowance into FFAMultiPlayerState so repeated
  invalid moves eventually resolve instead of retrying forever.
- Return the real done flag from step() on an invalid move so an exhausted
  error allowance can end the game.
- Add an _invalid() helper: on exhausting the allowance the offender
  forfeits to the opponent (matches the repo-wide invalid-move convention).
- Drop the dead self.rewards writes in _process_judge_decision; rewards
  flow through state.set_winners()/close().
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.

2 participants