The Sure Hit That Missed One Time in 256 — JavaScript Bug Hunt

Modelled on the first-generation Pokémon games (Red and Green in Japan in 1996, Red and Blue abroad): the accuracy check drew a random byte from 0 to 255…

  • Language: JavaScript
  • Layer: Frontend
  • Difficulty: Easy
  • Concepts: Randomness, Games
  • Modelled on: Pokémon Red/Blue · 1996
  • Visible tests: a 100% move hits on a low roll; a 100% move hits on the highest roll
  • Reward: 50 XP for a complete fix

Briefing

Modelled on the first-generation Pokémon games (Red and Green in Japan in 1996, Red and Blue abroad): the accuracy check drew a random byte from 0 to 255 and hit only if it was strictly less than the move's accuracy scaled to that range. Scaled accuracy tops out at 255, so a roll of 255 always missed — even a "100% accurate" move missed one time in 256.

This reconstruction is the battle screen's hit check, with the random source injected.

Fix willHit so a 100%-accurate move always hits.

Bug report

BUG-1-IN-256 · Priority: Medium · Reported by: players, for decades

willHit(accuracyPct, rng) — rng() returns an integer roll in 0..255.

  • accuracyPct >= 100: always hits, and rng is NOT called (the roll is not drawn)
  • otherwise: draw exactly one roll; hit iff roll < threshold(accuracyPct), where threshold(p) = floor(p * 255 / 100)

hitsOutOf256(p) counts the hits over every possible roll: 256 for a 100% move, 127 for a 50% move.

Observed: a 100% move misses when the roll is 255.

Logs

[battle] TACKLE acc=100 roll=255 -> MISSED

The code as shipped

src/battle/accuracy.js (editable)

var rules = require("./rules");

// Accuracy is a percentage, scaled to the range of the random byte.
exports.threshold = function (accuracyPct) {
  var t = Math.floor(accuracyPct * rules.MAX_ROLL / 100);
  return t > rules.MAX_ROLL ? rules.MAX_ROLL : t;
};

exports.willHit = function (accuracyPct, rng) {
  return rng() < exports.threshold(accuracyPct);
};

exports.hitsOutOf256 = function (accuracyPct) {
  var hits = 0;
  for (var roll = 0; roll <= rules.MAX_ROLL; roll++) {
    if (exports.willHit(accuracyPct, function () { return roll; })) hits++;
  }
  return hits;
};

Read-only context: src/battle/rules.js.

Open the hunt to edit the files, run the visible tests and submit against the hidden ones. More JavaScript bug hunts.