Something went wrong. Try again.
Web frontend and supporting services for lance.blue
Something went wrong. Try again.
6.4 kB · 159 lines
JavaScript
at main
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160/** * What a firepower curve says, as opposed to what it looks like. * * The drawing is geometry and is checked by looking at it. The reading is not: * "where is this design at its best" has a wrong answer, and the wrong answers * are the interesting ones - a design with two separate peaks, a design within * a whisker of its own best over five hexes running, a design that lands * nothing at all. Each of those has been drawn on a chart at some point and * described in one line of text, and the line is the half a player quotes. * * Run with `npm test`. */import { test } from "node:test";import assert from "node:assert/strict";
import { REACH, bestHexes, describe, liveSpan, sayDamage, sayHexes, scaleAcross, scaleFor, totalCurve,} from "../src/curve.ts";
/** A curve of the right length with damage at the hexes named. */function curve(at) { return Array.from({ length: REACH }, (_, index) => at[index + 1] ?? 0);}
test("one hex is one run", () => { assert.deepEqual(bestHexes(curve({ 1: 5, 2: 9, 3: 5 })), [[2, 2]]); assert.equal(sayHexes(bestHexes(curve({ 1: 5, 2: 9, 3: 5 }))), "2");});
test("adjacent hexes within a twentieth are one run", () => { // 27.5, 27.0 and 26.8 are one answer, not three. An Awesome is this shape. const awesome = curve({ 3: 20, 4: 27.5, 5: 27, 6: 26.8, 7: 18 }); assert.deepEqual(bestHexes(awesome), [[4, 6]]); assert.equal(sayHexes(bestHexes(awesome)), "4–6");});
test("how near counts as near scales with the design", () => { // The reason it is a share and not a point. Half a point is most of what a // scout lands and nothing at all to an assault, and a flat point read the // two the wrong way round: it made every hex of the scout's curve its best // and cut the assault's answer down to the single hex that happened to win. const scout = curve({ 1: 2, 2: 1.9, 3: 1.2 }); assert.deepEqual(bestHexes(scout), [[1, 2]], "1.2 is not 2 with rounding");
const assault = curve({ 3: 40, 4: 38.5, 5: 37 }); assert.deepEqual( bestHexes(assault), [[3, 4]], "38.5 of 40 is the same answer", );});
test("two peaks with a gap stay two runs", () => { // The case a single "best range" cannot express: short-range guns and a // launcher, equal at four hexes and again at eleven, nothing between. const both = curve({ 4: 30, 5: 12, 10: 12, 11: 29.5 }); assert.deepEqual(bestHexes(both), [ [4, 4], [11, 11], ]); assert.equal(sayHexes(bestHexes(both)), "4, 11");});
test("a design that lands nothing has no best range", () => { const nothing = curve({}); assert.deepEqual(bestHexes(nothing), []); assert.equal(describe(nothing), "lands nothing at any range."); assert.equal( describe(nothing, "Buster BC XXI HaulerMech"), "Buster BC XXI HaulerMech: lands nothing at any range.", );});
test("the description names the hexes and rounds the damage", () => { assert.equal( describe(curve({ 3: 49.02 }), "Atlas AS7-D"), "Atlas AS7-D: best 49 damage at hex 3.", ); assert.equal( describe(curve({ 1: 8.34, 2: 8.3 })), "best 8 damage at hexes 1–2.", );});
test("damage is written the way a player would say it", () => { // Whole points. The model is an expectation over dice and nobody picks // between two designs on a tenth of one. assert.equal(sayDamage(33.4), "33"); assert.equal(sayDamage(10), "10"); assert.equal(sayDamage(9.96), "10"); assert.equal(sayDamage(8.34), "8"); assert.equal(sayDamage(0), "0"); // Except where the rounding would say "no guns" about a machine that has // one. A design landing a fifth of a point is not a design landing nothing. assert.equal(sayDamage(0.2), "<1"); assert.equal(sayDamage(0.5), "1");});
test("a force lands what its designs land, hex by hex", () => { const atlas = curve({ 1: 40, 2: 45, 3: 49 }); const catapult = curve({ 5: 28, 6: 29 }); const together = totalCurve([atlas, catapult]); assert.equal(together.length, REACH); assert.equal(together[2], 49); assert.equal(together[5], 29); // Nobody is at their own best where the force is: the Atlas peaks at three // and the Catapult at six, and the force's answer is the Atlas's. assert.deepEqual(bestHexes(together), [[3, 3]]);});
test("an empty force is a curve of noughts rather than an empty array", () => { // The chart is drawn from whatever this returns, and a short array would // draw a curve that stops halfway across the board. assert.equal(totalCurve([]).length, REACH); assert.deepEqual(bestHexes(totalCurve([])), []);});
test("a shared scale is the tallest curve in the set, and never nought", () => { assert.equal(scaleFor([curve({ 1: 8 }), curve({ 3: 49 })]), 49); // A screen of unarmed designs still divides by this. assert.equal(scaleFor([curve({}), curve({})]), 1); assert.equal(scaleFor([]), 1);});
test("a curve is alive between its first and last hex that lands anything", () => { // What the faded ends of the drawing are cut on. A missile boat is blind up // close and everything is blind past its longest gun, and neither is a // taper to nothing - both are flat nought with a live stretch between. assert.deepEqual(liveSpan(curve({ 3: 12, 4: 14, 18: 6 })), [2, 17]); // A hex of nought inside the live stretch stays inside it: a gap between // two bands of range is still range the design is on the board for. assert.deepEqual(liveSpan(curve({ 1: 8, 2: 0, 3: 8 })), [0, 2]); assert.equal(liveSpan(curve({})), null);});
test("a search's shared scale ignores the tail that would flatten it", () => { // What one scale over a whole result set has to survive: a filter as broad // as mass<=55 holds designs landing over a hundred, and drawing three // thousand rows to that leaves every one of them a flat line on the axis. const set = [ ...Array.from({ length: 19 }, () => curve({ 3: 20 })), curve({ 3: 120 }), ]; assert.equal(scaleFor(set), 120, "the true maximum is still the maximum"); assert.equal(scaleAcross(set), 20, "and is not what the rows are drawn to"); // The unarmed do not drag it down - a filter catching four hundred haulers // would otherwise halve the scale the armed designs are drawn to. assert.equal(scaleAcross([curve({}), curve({}), curve({ 1: 30 })]), 30); assert.equal(scaleAcross([]), 1); assert.equal(scaleAcross([curve({})]), 1);});