GP di Fortezza: guida semplice alla bona e Seria (si tiene premuto per il gas, lasciando si frena, lo sterzo va da solo e troppo forte in curva si scivola nella paglia), per il telefono; Ginocchio in terra resta con lo sterzo vero; prova nel browser del GP (Andrea)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GiECd9KMfjthRUnujCGSzZ
This commit is contained in:
@@ -0,0 +1,56 @@
|
||||
// Il GP di Fortezza nel browser vero: alla bona e seria la guida semplice (solo gas, lasciando si frena), a ginocchio
|
||||
// in terra lo sterzo vero. npm run browser:gara — schermate in /tmp/regolo-gara.
|
||||
import { chromium } from 'playwright';
|
||||
import { mkdirSync } from 'node:fs';
|
||||
import assert from 'node:assert/strict';
|
||||
import { staticServer } from './helpers.mjs';
|
||||
|
||||
const out = process.env.OUT ?? '/tmp/regolo-gara';
|
||||
mkdirSync(out, { recursive: true });
|
||||
const server = await staticServer();
|
||||
let browser;
|
||||
const errors = [];
|
||||
|
||||
try {
|
||||
browser = await chromium.launch({ args: ['--autoplay-policy=no-user-gesture-required', '--use-gl=angle', '--use-angle=swiftshader', '--enable-unsafe-swiftshader'] });
|
||||
for (const [name, mobile, viewport, level] of [
|
||||
['touch', true, { width: 844, height: 390 }, 'seria'],
|
||||
['portrait', true, { width: 390, height: 844 }, 'bona'],
|
||||
['desktop', false, { width: 1280, height: 860 }, 'male'],
|
||||
]) {
|
||||
const page = await browser.newPage({ viewport, hasTouch: mobile, isMobile: mobile });
|
||||
page.on('pageerror', e => errors.push(e.message));
|
||||
await page.goto(`http://127.0.0.1:${server.port}/`);
|
||||
await page.click('#splash');
|
||||
await page.click('#new-game');
|
||||
await page.click('#rione [data-rione="campomigliaio"]');
|
||||
await page.click('#skip-intro');
|
||||
await page.evaluate(async level => {
|
||||
const { settle } = await import('/tests/helpers.mjs');
|
||||
settle(game); game.run({ closeup: 'gara', level }); settle(game);
|
||||
}, level);
|
||||
await page.waitForSelector('#bocce-controls:not([hidden])');
|
||||
// Salta la presentazione dei piloti e aspetta il via.
|
||||
await page.evaluate(async () => { const g = await import('/src/engine/gara.js'); while (game.closeup.step === 'intro') g.press(game.closeup); });
|
||||
await page.waitForFunction(() => game.closeup.step === 'race', null, { timeout: 15000 });
|
||||
const easy = level !== 'male';
|
||||
for (const id of ['#bocce-left', '#bocce-right', '#gara-brake', '#gara-pad'])
|
||||
assert.equal(await page.locator(id).isVisible(), !easy, `${name}: ${id} ${easy ? 'nascosto' : 'visibile'}`);
|
||||
assert.equal(await page.locator('#bocce-power').isVisible(), !easy, 'la sensibilità solo con lo sterzo vero');
|
||||
// Il pulsante Gas accende il gas; un altro tocco lo spegne e nella guida semplice si frena.
|
||||
if (mobile) await page.locator('#bocce-throw').tap(); else await page.locator('#bocce-throw').click();
|
||||
await page.waitForFunction(() => game.closeup.riders.find(r => r.id === 'andrea').v > 40, null, { timeout: 15000 });
|
||||
await page.screenshot({ path: `${out}/${name}-${level}.png` });
|
||||
if (mobile) await page.locator('#bocce-throw').tap(); else await page.locator('#bocce-throw').click();
|
||||
const v = await page.evaluate(() => game.closeup.riders.find(r => r.id === 'andrea').v);
|
||||
await page.waitForTimeout(300);
|
||||
const after = await page.evaluate(() => game.closeup.riders.find(r => r.id === 'andrea').v);
|
||||
assert.ok(after < v, `${name}: senza gas rallenta (${v.toFixed(0)} → ${after.toFixed(0)})`);
|
||||
await page.close();
|
||||
}
|
||||
assert.deepEqual(errors, []);
|
||||
console.log(`ok: schermate in ${out}`);
|
||||
} finally {
|
||||
await browser?.close();
|
||||
server.kill();
|
||||
}
|
||||
+40
-6
@@ -1,6 +1,6 @@
|
||||
import test from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import { SWIPE, setPower, newGara, update, press, presenting, INTRO, release, cancel, shoot, key, steerButton, brakeButton, aimScreen, steering, status, button, standings, player, rider, limitAt, pointAt, TRACK, CURVES, PICKUPS, BRAKE, VERGE, LAPS, COUNTDOWN, RIDERS } from '../src/engine/gara.js';
|
||||
import { SIMPLE, simple, simpleLimit, SWIPE, setPower, newGara, update, press, presenting, INTRO, release, cancel, shoot, key, steerButton, brakeButton, aimScreen, steering, status, button, standings, player, rider, limitAt, pointAt, TRACK, CURVES, PICKUPS, BRAKE, VERGE, LAPS, COUNTDOWN, RIDERS } from '../src/engine/gara.js';
|
||||
import { piloti } from '../src/story/piloti.js';
|
||||
import { story } from '../src/story/story.js';
|
||||
import { Game } from '../src/engine/game.js';
|
||||
@@ -58,7 +58,7 @@ test('i piloti sono dati: motore da 1 a 6 e testa da 1 a 5 danno velocità, acce
|
||||
});
|
||||
|
||||
test('il semaforo, poi il gas: tenendo premuto si va, lasciando si rallenta, il freno vince sul gas', () => {
|
||||
const c = newGara(3, { level: 'seria', riders: RIDERS });
|
||||
const c = newGara(3, { level: 'seria', riders: RIDERS, simple: false });
|
||||
for (const r of RIDERS) assert.ok(press(c, 7), r.id);
|
||||
assert.equal(c.step, 'start', 'un tocco per pilota e la presentazione è finita');
|
||||
assert.equal(c.holding, false, 'senza dare gas');
|
||||
@@ -161,7 +161,7 @@ test('l’origine segue gli swipe lunghi e si può correggere; rilascio e annull
|
||||
});
|
||||
|
||||
test('alla bona si completano tre giri usando solo un dito, senza tasti o pulsanti', () => {
|
||||
const c = race(newGara(5, { level: 'bona', riders: piloti.filter(p => p.consenso !== null) }));
|
||||
const c = race(newGara(5, { level: 'bona', riders: piloti.filter(p => p.consenso !== null), simple: false }));
|
||||
aimScreen(c, [320, 180], 'bot'); press(c, 'bot');
|
||||
for (let t = 0; t < 180 && c.step === 'race'; t += 1 / 60) {
|
||||
swipeTo(c, pointAt(player(c).s + 50));
|
||||
@@ -198,7 +198,7 @@ test('la presentazione: uno alla volta arrivano in griglia col motorino, poi il
|
||||
});
|
||||
|
||||
test('sempre a gas e dritto si finisce nella paglia; con giudizio alla bona si vince', () => {
|
||||
const wild = newGara(5, { level: 'bona', riders: piloti.filter(p => p.consenso !== null) });
|
||||
const wild = newGara(5, { level: 'bona', riders: piloti.filter(p => p.consenso !== null), simple: false });
|
||||
skip(wild);
|
||||
run(wild, COUNTDOWN + 60, () => true);
|
||||
assert.ok(wild.heard.has('gara-fuori:andrea'));
|
||||
@@ -206,7 +206,7 @@ test('sempre a gas e dritto si finisce nella paglia; con giudizio alla bona si v
|
||||
assert.equal(wild.step, 'race', 'dritto non si arriva');
|
||||
const heard = new Set();
|
||||
for (const seed of [1, 2, 3, 4]) {
|
||||
const c = newGara(seed, { level: 'bona', riders: piloti.filter(p => p.consenso !== null) });
|
||||
const c = newGara(seed, { level: 'bona', riders: piloti.filter(p => p.consenso !== null), simple: false });
|
||||
skip(c); setPower(c, 1); // a sensibilità piena: il dito risponde subito
|
||||
for (const k of run(c, COUNTDOWN + 120, careful)) heard.add(k);
|
||||
assert.equal(c.step, 'result'); assert.equal(c.result.winner, 'player', `seme ${seed}`);
|
||||
@@ -219,7 +219,7 @@ test('sempre a gas e dritto si finisce nella paglia; con giudizio alla bona si v
|
||||
|
||||
test('alla sensibilità di partenza (bassa) lo stesso pilota non finisce mai nella paglia', () => {
|
||||
for (const seed of [1, 2, 3]) {
|
||||
const c = newGara(seed, { level: 'bona', riders: piloti.filter(p => p.consenso !== null) });
|
||||
const c = newGara(seed, { level: 'bona', riders: piloti.filter(p => p.consenso !== null), simple: false });
|
||||
skip(c); assert.equal(c.sens, SWIPE.sens);
|
||||
run(c, COUNTDOWN + 120, careful);
|
||||
assert.equal(c.step, 'result'); assert.equal(c.result.offs, 0, `seme ${seed}`);
|
||||
@@ -270,3 +270,37 @@ test('nella storia: dal Trappola l\'Arcu scherza sul Betino, poi la sfida; prima
|
||||
// Il Betino, lassù: solo Andrea ne parla.
|
||||
g.act('use', 'betino'); assert.ok(settle(g).every(s => s.who === 'andrea'));
|
||||
});
|
||||
|
||||
// La guida semplice (Andrea, 29 ottobre: dal telefono lo sterzo era ingiocabile): alla bona e seria si tiene premuto
|
||||
// per il gas e lasciando si frena, lo sterzo va da solo; troppo forte in curva si scivola fuori. Ginocchio in terra no.
|
||||
test('guida semplice: alla bona e seria sì, a ginocchio in terra no; lasciando si frena e lo sterzo va da solo', () => {
|
||||
const riders = piloti.filter(p => p.consenso !== null);
|
||||
assert.equal(simple(newGara(1, { level: 'bona', riders })), true);
|
||||
assert.equal(simple(newGara(1, { level: 'seria', riders })), true);
|
||||
assert.equal(simple(newGara(1, { level: 'male', riders })), false);
|
||||
const c = race(newGara(1, { level: 'bona', riders }));
|
||||
run(c, 2, () => true);
|
||||
const v = player(c).v; assert.ok(v > 40);
|
||||
run(c, 0.3, () => false);
|
||||
assert.ok(player(c).v < v - BRAKE * 0.3 + 5, 'lasciando frena, non solo rallenta');
|
||||
assert.match(status(c), /Freno\./);
|
||||
// Le frecce non sterzano: lo sterzo segue la strada.
|
||||
key(c, 'ArrowLeft', true); run(c, 2, () => true); key(c, 'ArrowLeft', false);
|
||||
assert.ok(Math.abs(player(c).lat) < 9, 'resta in strada');
|
||||
});
|
||||
|
||||
test('guida semplice: sempre a tutto gas si finisce nella paglia; mollando prima delle curve no, e alla bona si vince', () => {
|
||||
const riders = piloti.filter(p => p.consenso !== null);
|
||||
// Molla quando, frenando da qui, arriverebbe a una curva sopra il limite della guida semplice.
|
||||
const wise = c => { const r = player(c), h = r.v * r.v / (2 * BRAKE) + 10; for (let d = 0; d <= h; d += 4) { const a = simpleLimit(r, r.s + d); if (r.v * r.v > a * a + 2 * BRAKE * d) return false; } return true; };
|
||||
for (const seed of [1, 2]) {
|
||||
const wild = race(newGara(seed, { level: 'bona', riders }));
|
||||
run(wild, 120, () => true);
|
||||
assert.ok(wild.result.offs > 0, 'a tutto gas si esce');
|
||||
const c = race(newGara(seed, { level: 'bona', riders }));
|
||||
run(c, 120, wise);
|
||||
assert.equal(c.result.offs, 0); assert.equal(c.result.falls, 0, 'le buche si scansano');
|
||||
assert.equal(c.result.winner, 'player', `seme ${seed}`);
|
||||
}
|
||||
assert.ok(SIMPLE.slide > 0);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user