Benchmark report

Battleship vs. Jev

TypeSafe's Jev is not a generative model. You hand it a state and typed questions, and it hands back probability distributions. So: can it play Battleship?

Battleship is a good test for a judgement model. The rules are trivial, the state is small, and there is a strong non-model baseline to measure against — so any credit the model takes has to be earned against code that already plays well.

Jev answers three kinds of question: a Choice over named options, a Score against ordered levels, and a boolean probability. Every answer carries a distribution, not just a pick. For Battleship that is the whole game: ask which cell holds a ship, and the per-option probabilities are a heatmap of where the model thinks the fleet is.

The design constraint comes from TypeSafe's own documentation. Jev is not a calculator, it loses accuracy as irrelevant state grows, and it does better on semantic descriptions than on positions it has to derive. So every rule check, every placement count and every probability calculation lives in code. The model is only ever asked to judge between options code has already established are legal.

Five players

One axis runs through all of them: how much of the thinking is code, and how much is the model.

StrategyModel callsWhat it does
Random0 Uniform among untried cells. The floor.
Hunt / Target0 Parity search, then works outwards from a hit.
Density0 Counts every valid remaining-ship placement per cell. The strongest code player.
Jev pure1 / shot One Choice over every untried cell, from raw board state.
Jev hybrid1 / shot Code ranks the top 16 and describes each; the model compares those.
Density and Jev pure are opposite ends of the same spectrum — pure code against pure model, on identical boards. Jev hybrid sits between them.

The difference, on one board

Both strategies face the position below. A ship has been hit at H8 and not sunk; another was sunk at F5–F7. Jev pure is handed all 88 untried cells as options, every one labelled identically — "A cell that has not been fired at yet." All the signal sits in 2,791 characters of board state it must parse unaided.

Jev hybrid is handed 16, each described in words: "directly continues 1 hit in a row below; has room for the longest ship still afloat; is in the open middle of the board."

lower rankhigher rank
The real position after 12 shots, seed 11. Shaded cells are the 16 the code shortlists for Jev hybrid, banded by rank. Rust is a live hit; dark rust a sunk ship; flat grey a miss. Every unshaded cell is one the model is never asked about.

Probability is a magnitude, so the ramp is one hue in six discrete steps ordered by lightness — it survives greyscale and any colour vision, and discrete bands separate cells far better than a continuous fade, where low values vanish.

Results

60 games per strategy, all five playing the same 60 layouts, so every comparison is paired. Lower is better: 17 shots is a perfect game, 100 is the worst possible.

0255075100 shots
Mean shots to sink the fleet, with 95% confidence intervals. Note the overlap between Jev hybrid and Density — that overlap is the result.
StrategyMeanMedianSD BestWorstAcc.Tokens / gameCost
Jev hybrid (top 16) 46.047.09.6 267137% 54,365$0.12
Probability density 48.349.011.6 256935%
Hunt / Target 51.952.07.6 336433%
Jev pure (per-cell list) 85.588.512.2 4810020% 297,315$0.65
Random 95.397.05.3 6910018%
Paired comparisonDifference95% CIpVerdict
Jev hybrid − Density −2.22[−5.11, 0.68]0.13 not distinguishable
Jev hybrid − Hunt/Target −5.90[−8.96, −2.84]0.00015 significant
Density − Hunt/Target −3.68[−7.47, 0.10]0.056 not distinguishable
Jev pure − Random −9.78[−12.76, −6.80]1.3e−10 significant
Jev pure − Hunt/Target +33.57[30.08, 37.05]<1e−15 significant
Paired t-tests over the same 60 layouts, n = 60.

Two findings

Finding 01

Choosing from ~90 cells is close to guessing.

Given the raw board and every untried cell as an option, Jev needs 85.5 shots against random's 95.3. The 9.8-shot gap is real — it is reading the board — but it loses to Hunt/Target, a fifty-line heuristic, by 33.6 shots, and lost on 59 of 60 layouts. It cost $0.65 to finish barely ahead of random.

Two documented traits explain it. Every option is labelled identically, so nothing in the option list helps. And probabilities come back rounded to two decimals, so spread across ~90 options most of the distribution collapses to zero — on a typical shot only a handful of cells carry any value at all.

Finding 02

With a shortlist, it matches the code baseline — but does not beat it.

With code ranking the top 16 and describing each in words, Jev reaches 46.0 shots, comfortably past Hunt/Target (p = 0.00015). Against Density it is nominally ahead by 2.2 shots — but the confidence interval spans zero, p is 0.13, and it won 31 of 60 layouts. That is a coin flip.

So the honest reading is that Jev hybrid matches the best code-only player rather than beating it. This run could detect a 4.7-shot difference; the observed gap is half that. Settling it needs roughly 260 games per strategy — about two and a half hours and $0.80.

Put together: the model does real work, but its contribution shows up only once code has reduced the problem to a short list of described options. Asked to find a ship on a raw board, it is far worse than a simple hand-written rule. That is exactly consistent with the documented jaggedness — and it means the configuration where Jev looks good is also the one where code has done the hard part.

Every setting, and what it changes

The interface exposes exactly the dimensions that change what is being measured. Each one is in the URL, so a link reproduces a run.

strategy
Which of the five plays. Jev pure measures the model unaided; Jev hybrid measures the model and the code together. The three code strategies make no API calls and finish instantly.
representation
How the board is written into the model's state. Per-cell list spells out every cell with no interpretation (2,791 chars). Row strings draws a compact grid with a legend (777 chars) — cheapest, but finding a cell means counting along a string, which Jev is documented to be unreliable at. Semantic candidates has code do the geometry and hand over prose (266 chars). Shown only for model strategies.
layout
Which family the defending fleet is drawn from: random, edge, centre, adversarial, or place it yourself. This changes the answer — see below.
seed
The same seed gives the same fleet, so two runs are comparable. Change it between runs; a single game's spread is ±8 shots, so one game measures nothing.
top K
How many candidates Jev hybrid offers. Default 16, set by coverage rather than score: a hit ship's frontier averages 9.9 cells, and at 8 the shortlist held only 65% of them — code was deciding by omission most of the time.
JEV_MOCK
A server-side switch that replaces the model with code-side density, for demos without spending calls. Deliberately not a UI control or a URL parameter: it changes what the numbers mean rather than what is measured, so no link and no stray click can enable it, and the page shows a banner while it is on.

The fleet layout decides the answer

The most surprising result was not about the model at all. Density counts placements under a uniform prior, so uniform-random layouts are the one case it is built for. Measured over 200 layouts per family, the ranking between the two code baselines inverts:

Layout familyDensityHunt / TargetGap
Random43.451.8density +8.3
Edge52.350.1density −2.2
Adversarial53.049.8density −3.1
Mixed48.648.7level
On an empty board density rates the middle at 28.5 and the edge at 18.2, so it searches the middle first. An edge layout puts all 17 ship cells where it looks last.

This is a measurement bias, not a bug. Benchmarking only on uniform-random layouts tests density on precisely the distribution it assumes — and density is the bar the model is held to. The benchmark above therefore runs on mixed, and every result records its family.

Method and caveats

The game engine is pure deterministic code with no model involvement, covered by 226 unit tests. Every model call goes through a single client that logs the state, the questions, the response, latency, tokens, confidence and the model version.

  • One model version. Results hold for jev-1.13.0 only. Calling TypeSafe directly reports the build that answered; through Vercel AI Gateway only the requested alias comes back, so a silent model update would be invisible.
  • One layout family. mixed. Results are not comparable across families.
  • Accuracy is context, not the objective. Shots to sink the fleet is the benchmark.
  • Jev hybrid's score belongs to the pair. Only the comparison against density isolates the model's own contribution, and that comparison is currently inconclusive.

To reproduce:

npm run bench -- --transport direct --layouts mixed --games 60 \
  --strategies random,huntTarget,density,jevPure,jevHybrid --seed 1000

Every call's generation id is written to the JSON output, so any row in the results can be traced back to a specific request in the provider's logs.