1
0
Fork 0

Compare commits

..

No commits in common. "bf5468e4612048bce2fd33d2b22580d2f6c2cd19" and "3daa7a3601469ddbf03ed66b3734bb89f9e306ff" have entirely different histories.

2 changed files with 16 additions and 25 deletions

View file

@ -1,6 +1,6 @@
{
"name": "polaris-task-force",
"version": "0.2.19",
"version": "0.2.18",
"description": "Web app for the Arma 3 unit Polaris Task Force. Uses Next.js for client- and server-side rendering, with a Postgres database and some other neat libraries.",
"license": "MIT",
"type": "module",

View file

@ -188,7 +188,7 @@ export interface OpordScenario {
readonly operationName: string;
/** e.g. "TRIDENT" */
readonly objective: string;
/** Six-digit grid as digits only, e.g. "034672". */
/** Eight-digit grid as digits only, e.g. "03467219". */
readonly grid: string;
/** Three-digit degrees, e.g. 47. */
readonly azimuth: number;
@ -217,9 +217,9 @@ export interface OpordScenario {
readonly enRouteMin: number;
}
/** Formats a 6-digit grid Arma map style: three digits, hyphen, three digits, e.g. "034-672". */
/** Formats an 8-digit grid as two 4-digit halves, e.g. "0346 7219". */
export function formatOpordGrid(grid: string): string {
return grid.length === 6 ? `${grid.slice(0, 3)}-${grid.slice(3)}` : grid;
return grid.length === 8 ? `${grid.slice(0, 4)} ${grid.slice(4)}` : grid;
}
/** Buckets a 1-359 azimuth onto the eight winds; 359 and 1 both resolve to NORTH. */
@ -231,7 +231,7 @@ export function generateOpordScenario(seed: number): OpordScenario {
const rng = mulberry32(seed);
const operationName = `${pick(rng, OPERATION_ADJECTIVES)} ${pick(rng, OPERATION_NOUNS)}`;
const objective = pick(rng, OBJECTIVE_NAMES);
const grid = Array.from({ length: 6 }, () => Math.floor(rng() * 10)).join("");
const grid = Array.from({ length: 8 }, () => Math.floor(rng() * 10)).join("");
const azimuth = pickInt(rng, 1, 359);
const distanceKm = pickInt(rng, 4, 24);
const hHourMinutes = pickInt(rng, 0, 23) * 100 + pick(rng, [0, 15, 30, 45]);
@ -327,31 +327,22 @@ export function buildOpordQuestions(
CODEWORDS.filter((word) => word !== scenario.codeword && word !== scenario.abortCodeword),
).slice(0, 3);
const gridVariants = [
scenario.grid.split("").reverse().join(""),
scenario.grid.slice(3) + scenario.grid.slice(0, 3),
scenario.grid
.split("")
.map((digit) => String((Number(digit) + 1) % 10))
.join(""),
scenario.grid
.split("")
.map((digit) => String((Number(digit) + 2) % 10))
.join(""),
];
// A palindrome or half-repeating grid collapses one variant onto the answer;
// dedupe first so the question always shows four distinct options.
const gridDistractors = gridVariants
.filter((value, index) => value !== scenario.grid && gridVariants.indexOf(value) === index)
.slice(0, 3);
const gridBuilder = () =>
// The objective grid is the core skill: always asked first.
choiceQuestion(
"grid",
"What is the 6-digit grid of the objective?",
"What is the 8-digit grid of the objective?",
formatOpordGrid(scenario.grid),
gridDistractors.map((value) => formatOpordGrid(value)),
[
formatOpordGrid(scenario.grid.split("").reverse().join("")),
formatOpordGrid(scenario.grid.slice(4) + scenario.grid.slice(0, 4)),
formatOpordGrid(
scenario.grid
.split("")
.map((digit) => String((Number(digit) + 1) % 10))
.join(""),
),
],
rng,
);