La macchina del tempo: dall'Arcu («Bei tempi quando qui si faceva i pokerini…») al Barrettino del 10 luglio 1997 col viaggio sul cruscotto, Vannino e Pierino Parigi, e il pokerino a cinque carte col cambio; l'Arcu in Via Liguri Magelli più grande (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,86 @@
|
||||
import test from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import * as P from '../src/engine/poker.js';
|
||||
import { drawPoker, cardAt, HAND } from '../src/engine/poker-render.js';
|
||||
import { Game, MINIGAMES, TRIP } from '../src/engine/game.js';
|
||||
import { story } from '../src/story/story.js';
|
||||
import { settle } from './helpers.mjs';
|
||||
|
||||
const card = s => ({ rank: s.slice(0, -1), suit: { c: 'cuori', q: 'quadri', f: 'fiori', p: 'picche' }[s.at(-1)] });
|
||||
const hand = s => s.split(' ').map(card);
|
||||
|
||||
test('i punti del mazzo corto: il colore batte il full, A-7-8-9-10 è la scala più bassa', () => {
|
||||
const order = ['Ac Kf 9p 8q 7c', '7c 7f Kp 9q 8c', '7c 7f 9p 9q Ac', 'Jc Jf Jp 9q 8c', 'Ac 7f 8p 9q 10c', '7c 8f 9p 10q Jc',
|
||||
'Kc Kf Kp 9q 9c', 'Ac Kc 9c 8c 7c', 'Qc Qf Qp Qq 7c', '7c 8c 9c 10c Jc'];
|
||||
const scores = order.map(h => P.evaluate(hand(h)));
|
||||
for (let i = 1; i < scores.length; i++) assert.ok(P.compare(scores[i], scores[i - 1]) > 0, `${order[i]} batte ${order[i - 1]}`);
|
||||
assert.equal(P.handName(hand('Ac Kc 9c 8c 7c')), 'colore');
|
||||
assert.ok(P.compare(P.evaluate(hand('Ac Af 9p 8q 7c')), P.evaluate(hand('Ac Af 9p 8q Kc'))) < 0, 'a parità di coppia contano le carte spaiate');
|
||||
});
|
||||
|
||||
test('una partita intera: le fiches non si perdono, finisce sempre, e chi sa giocare vince più di chi vede sempre', () => {
|
||||
const play = (seed, level, brain) => {
|
||||
const c = P.newPoker(seed, { level });
|
||||
for (let i = 0; i < 20000 && c.step !== 'result'; i++) {
|
||||
if (P.myTurn(c)) P.choose(c, brain(c)); else if (P.canDraw(c)) { for (const k of P.cpuDiscards({ ...c, skill: P.LEVELS.male }, 'andrea')) P.play(c, k); P.choose(c, 'cambia'); }
|
||||
else if (c.step === 'show') P.advance(c); else P.update(c, 1);
|
||||
const sum = P.SEATS.reduce((n, s) => n + c.chips[s], 0) + (c.step === 'show' || c.step === 'result' ? 0 : c.pot);
|
||||
assert.equal(sum, P.START * 3);
|
||||
}
|
||||
assert.equal(c.step, 'result');
|
||||
return c.result.chips.andrea;
|
||||
};
|
||||
const smart = c => { const s = P.strength(c.cards.andrea); return s > 0.5 && P.canRaise(c) ? 'rilancio' : s > 0.15 || !P.toCall(c) ? 'vedo' : 'lascio'; };
|
||||
let a = 0, b = 0;
|
||||
for (let seed = 1; seed <= 60; seed++) { a += play(seed, 'bona', smart); b += play(seed, 'bona', () => 'vedo'); }
|
||||
assert.ok(a > b, `con giudizio ${a}, vedendo sempre ${b}`);
|
||||
});
|
||||
|
||||
test('i comandi di Andrea: il cambio si sceglie toccando (al massimo 4), le puntate coi pulsanti', () => {
|
||||
const c = P.newPoker(3);
|
||||
while (!P.myTurn(c)) P.update(c, 1);
|
||||
const moves = P.moves(c).map(m => m.id);
|
||||
assert.deepEqual(moves, ['lascio', 'vedo', 'rilancio']);
|
||||
assert.ok(P.choose(c, 'vedo'));
|
||||
while (!P.canDraw(c) && c.step !== 'show') P.update(c, 1);
|
||||
if (P.canDraw(c)) {
|
||||
assert.equal(cardAt(c, [HAND.x + 5, HAND.y + 5]), 0);
|
||||
for (const i of [0, 1, 2, 3, 4]) P.play(c, i);
|
||||
assert.equal(c.selected.size, 4, 'al massimo quattro');
|
||||
assert.ok(P.choose(c, 'cambia'));
|
||||
assert.equal(c.changed.andrea, 4);
|
||||
}
|
||||
});
|
||||
|
||||
test('il disegno del pokerino non cambia lo stato', () => {
|
||||
const calls = [], ctx = new Proxy({}, { get: (o, k) => k in o ? o[k] : (...args) => calls.push([k, ...args]) });
|
||||
const c = P.newPoker(9);
|
||||
const before = JSON.stringify({ ...c, selected: [...c.selected] });
|
||||
drawPoker(ctx, c);
|
||||
assert.equal(JSON.stringify({ ...c, selected: [...c.selected] }), before);
|
||||
assert.ok(calls.some(([op, t]) => op === 'fillText' && /POKERINO/.test(t)));
|
||||
});
|
||||
|
||||
test('la macchina del tempo: l\'Arcu la fa comparire, il viaggio porta al Barrettino del 1997 e la porta riporta nel 2007', () => {
|
||||
assert.ok(MINIGAMES.poker);
|
||||
const g = new Game(story); g.go('via_liguri_magelli'); settle(g);
|
||||
assert.ok(!g.hotspot('macchina_tempo'));
|
||||
g.act('talk', 'arcu'); settle(g);
|
||||
g.choose(g.options().findIndex(o => o.text.startsWith('Bei tempi'))); settle(g);
|
||||
assert.ok(g.state.flags.macchina_trappola && g.hotspot('macchina_tempo'));
|
||||
g.choose(g.options().findIndex(o => o.text.startsWith('Ci si vede'))); settle(g);
|
||||
g.act('use', 'macchina_tempo'); settle(g);
|
||||
assert.equal(g.closeup?.id, 'viaggio');
|
||||
for (let t = 0; t < TRIP.end + 0.5 && g.closeup; t += 0.05) g.update(0.05);
|
||||
settle(g);
|
||||
assert.equal(g.state.scene, 'barrettino_1997');
|
||||
g.act('talk', 'tavola'); settle(g);
|
||||
g.choose(g.options().findIndex(o => o.text.startsWith('C\'è posto'))); settle(g);
|
||||
g.choose(g.options().findIndex(o => o.text === 'A fassi male.')); settle(g);
|
||||
assert.equal(g.closeup?.id, 'poker'); assert.equal(g.closeup.level, 'male');
|
||||
g.closeup.step = 'result'; g.closeup.result = { winner: 'player', chips: { andrea: 200, vannino: 60, pierino: 40 }, top: ['andrea'] };
|
||||
g.closeupClose(); settle(g);
|
||||
assert.ok(g.state.flags.poker_vinto);
|
||||
g.act('walk', 'porta'); settle(g);
|
||||
assert.equal(g.state.scene, 'via_liguri_magelli');
|
||||
});
|
||||
+10
-1
@@ -260,6 +260,8 @@ test('il libro dell\'oratorio: il primo piano si sfoglia, l\'ultima pagina è «
|
||||
|
||||
test('la mappa: ogni scena ci sta, i posti compaiono solo visti, il viaggio rispetta i dialoghi', () => {
|
||||
for (const [id, sc] of Object.entries(story.scenes)) {
|
||||
// Le scene del viaggio nel tempo (`viaggio`) non sono sulla mappa: ci si va solo con la macchina.
|
||||
if (sc.viaggio) { assert.ok(!sc.map, `${id}: nel passato la mappa non porta`); continue; }
|
||||
assert.ok(Array.isArray(sc.map), `${id} non è sulla mappa`);
|
||||
assert.ok(sc.map.every(v => v >= 0 && v <= 100), `${id} fuori dalla pianta`);
|
||||
}
|
||||
@@ -341,7 +343,14 @@ test('le strade vanno e tornano: niente sensi unici, e ogni posto si raggiunge d
|
||||
for (const b of to) assert.ok(exits[b]?.has(a), `da ${a} si va a ${b}, ma da ${b} non si torna a ${a}`);
|
||||
const seen = new Set([story.start.scene]), queue = [story.start.scene];
|
||||
while (queue.length) for (const b of exits[queue.shift()] ?? []) if (!seen.has(b)) { seen.add(b); queue.push(b); }
|
||||
for (const id of Object.keys(story.scenes)) assert.ok(seen.has(id), `${id} non si raggiunge`);
|
||||
for (const [id, sc] of Object.entries(story.scenes)) {
|
||||
if (!sc.viaggio) { assert.ok(seen.has(id), `${id} non si raggiunge`); continue; }
|
||||
// Una scena del viaggio nel tempo: ci porta un `go` (la fine del viaggio), e un `go` riporta in una scena vera.
|
||||
const text = JSON.stringify(story);
|
||||
assert.ok(text.includes(`"go":"${id}"`), `${id}: nessun viaggio ci porta`);
|
||||
const back = JSON.stringify(sc.hotspots).match(/"go":"([a-z_0-9]+)"/g)?.map(m => m.slice(6, -1)) ?? [];
|
||||
assert.ok(back.some(b => seen.has(b)), `${id}: non si torna indietro`);
|
||||
}
|
||||
});
|
||||
|
||||
test('la catena del ghiacciolo: Tosca, cedrata, stecco, gomma, griglia, chiavetta, casetta, torcia', () => {
|
||||
|
||||
Reference in New Issue
Block a user