Scopa agli 11 all'oratorio, e il tressette rivisto dopo la revisione critica di Codex
Scopa: toscane o napoletane (mattoni o denari), presa obbligatoria, la carta uguale prima delle somme, scelta fra più prese toccando la tavola, coi pulsanti o con frecce e Invio; scope (non all'ultima carta), carte, mattoni, settebello, primiera; tre livelli tarati (92, 64, 52%); test e prova nel browser. Tressette: fuori ai 21 presa per presa, vittoria subito definitiva (Esc non la cancella più), accuse dette al proprio turno e col seme che manca del tris, striscio e busso meno rigidi, il socio risponde al busso, tiene il 3 e il 2, non esce d'Asso scoperto, legge il volo; tastiera col fuoco sulla carta scelta, tavola descritta a parole, riepilogo che aspetta Andrea. Stesso Esc corretto anche nella scopa. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A1dxvtsZx8NE9fwjXUNDBr
This commit is contained in:
+61
-24
@@ -1,6 +1,6 @@
|
||||
import { test } from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import { DECK_CARDS, newTressette, accuse, legal, best, signalOk, reason, setSignal, play, collect, advance, update, observation, choose, knowledge, canPlay, finished, team, status, TARGET } from '../src/engine/tressette.js';
|
||||
import { DECK_CARDS, newTressette, accuse, accuseName, legal, best, signalOk, reason, setSignal, play, collect, advance, update, observation, choose, knowledge, canPlay, finished, team, status, TARGET } from '../src/engine/tressette.js';
|
||||
import { simulate, calibrate } from '../tools/calibrate_tressette.mjs';
|
||||
|
||||
const card = (suit, rank, deck = 'toscane') => DECK_CARDS[deck].find(a => a.suit === suit && a.rank === rank);
|
||||
@@ -30,18 +30,22 @@ test('accuse: napoletana 3 punti, tre o quattro Assi, 2 o 3 per 3 o 4 punti, anc
|
||||
assert.deepEqual(a.map(x => [x.kind, x.points]), [['napoletana', 3], ['buongioco', 3]]);
|
||||
assert.equal(accuse(hand([['cuori', '2'], ['picche', '2'], ['fiori', '2'], ['mattoni', '2']]))[0].points, 4);
|
||||
assert.deepEqual(accuse(hand([['cuori', 'Asso'], ['cuori', '2'], ['picche', '3']])), []);
|
||||
// Del tris si dice il seme che manca, così Andrea sa quello che sa l'avversario.
|
||||
const tris = accuse(hand([['picche', '3'], ['fiori', '3'], ['mattoni', '3']]), ['cuori', 'mattoni', 'fiori', 'picche'])[0];
|
||||
assert.equal(tris.missing, 'cuori'); assert.equal(accuseName(tris), 'tre 3, manca cuori');
|
||||
});
|
||||
|
||||
test('segni onesti: volo con l\'ultima, striscio con almeno due rimaste, busso con almeno una; solo chi esce', () => {
|
||||
const h = hand([['cuori', '4'], ['cuori', '5'], ['cuori', '6'], ['fiori', '7']]);
|
||||
assert.ok(signalOk(h, 3, [], 'volo')); assert.ok(!signalOk(h, 0, [], 'volo'));
|
||||
assert.ok(signalOk(h, 0, [], 'striscio')); assert.ok(!signalOk(h, 3, [], 'striscio'));
|
||||
assert.ok(signalOk(h, 0, [], 'busso')); assert.ok(!signalOk(h, 3, [], 'busso'));
|
||||
test('segni: volo con l\'ultima, striscio se ne resta un\'altra, busso sempre; solo chi esce', () => {
|
||||
const h = hand([['cuori', '4'], ['cuori', '5'], ['fiori', '7']]);
|
||||
assert.ok(signalOk(h, 2, [], 'volo')); assert.ok(!signalOk(h, 0, [], 'volo'));
|
||||
assert.ok(signalOk(h, 0, [], 'striscio')); assert.ok(!signalOk(h, 2, [], 'striscio'));
|
||||
assert.ok(signalOk(h, 0, [], 'busso')); assert.ok(signalOk(h, 2, [], 'busso'));
|
||||
assert.ok(!signalOk(h, 0, [{ who: 1, card: card('cuori', '7') }], 'busso'));
|
||||
const c = newTressette(5); c.current = 0; c.table = []; c.hands[0] = [...h];
|
||||
const c = newTressette(5); c.current = 0; c.table = []; c.hands[0] = [...h]; c.pending[0] = [];
|
||||
assert.ok(setSignal(c, 'volo')); assert.equal(play(c, 0), false); assert.match(c.refused, /Volo solo/);
|
||||
assert.equal(c.hands[0].length, 4, 'la carta resta in mano');
|
||||
assert.ok(play(c, 3)); assert.equal(c.table[0].signal, 'volo'); assert.equal(c.signal, null);
|
||||
assert.equal(c.hands[0].length, 3, 'la carta resta in mano');
|
||||
assert.equal(play(c, 0, 0, 'xyz'), false); assert.equal(c.refused, 'Segno non riconosciuto.');
|
||||
assert.ok(play(c, 2)); assert.equal(c.table[0].signal, 'volo'); assert.equal(c.signal, null);
|
||||
assert.ok(c.events.some(e => e.kind === 'card-volo'));
|
||||
});
|
||||
|
||||
@@ -52,30 +56,43 @@ test('la carta che non risponde al seme si rifiuta con la ragione', () => {
|
||||
assert.ok(canPlay(c)); assert.ok(play(c, 0));
|
||||
});
|
||||
|
||||
test('una smazzata: 10 prese, 11 punti fra terzi e ultima presa, accuse nel punteggio, poi la seconda', () => {
|
||||
test('una smazzata: accuse dette al proprio turno, 10 prese, sempre 11 punti fra terzi e ultima presa', () => {
|
||||
const c = newTressette(1234, { level: 'seria' });
|
||||
const accused = [0, 1].map(t => c.accuse.filter(a => team(a.who) === t).reduce((n, a) => n + a.points, 0));
|
||||
assert.deepEqual(c.score, accused);
|
||||
assert.deepEqual(c.score, [0, 0]); assert.deepEqual(c.accuse, [], 'prima di giocare nessuno ha accusato');
|
||||
const owed = c.pending.flat();
|
||||
assert.equal(c.current, (c.dealer + 1) % 4, 'esce chi sta a destra del mazziere');
|
||||
assert.ok(c.hands.every(h => h.length === 10));
|
||||
const firstDealer = c.dealer;
|
||||
while (c.step !== 'smazzata') {
|
||||
while (!['smazzata', 'result'].includes(c.step)) {
|
||||
if (canPlay(c)) { const m = choose(observation(c, 0), 'seria'); assert.ok(play(c, m.index, 0, m.signal)); }
|
||||
update(c, 20);
|
||||
if (c.tricks.length === 1) assert.equal(c.accuse.length, owed.length, 'dopo la prima presa hanno accusato tutti');
|
||||
}
|
||||
if (c.step === 'smazzata') {
|
||||
assert.equal(c.tricks.length, 10);
|
||||
assert.equal(c.summary.thirds[0] + c.summary.thirds[1], 35);
|
||||
assert.equal(c.summary.points[0] + c.summary.points[1], 11, 'i terzi avanzati sommano sempre a due');
|
||||
assert.deepEqual(c.score, [0, 1].map(t => c.summary.accused[t] + c.summary.points[t]));
|
||||
assert.ok(advance(c)); assert.equal(c.dealer, (firstDealer + 1) % 4); assert.equal(c.step, 'play');
|
||||
}
|
||||
assert.equal(c.tricks.length, 10);
|
||||
assert.equal(c.summary.thirds[0] + c.summary.thirds[1], 35);
|
||||
assert.ok([10, 11].includes(c.summary.points[0] + c.summary.points[1]), 'si perdono al più i terzi avanzati');
|
||||
assert.deepEqual(c.score, [0, 1].map(t => accused[t] + c.summary.points[t]));
|
||||
if (!finished(c)) { advance(c); assert.equal(c.dealer, (firstDealer + 1) % 4); assert.equal(c.step, 'play'); }
|
||||
});
|
||||
|
||||
test('si va ai 21: vince chi ci arriva per primo; pari sopra i 21 si continua', () => {
|
||||
const c = newTressette(3);
|
||||
c.step = 'smazzata'; c.score = [21, 21]; assert.ok(!finished(c)); advance(c); assert.equal(c.step, 'play');
|
||||
c.step = 'smazzata'; c.score = [TARGET, 17]; advance(c); assert.equal(c.step, 'result'); assert.equal(c.result.winner, 'player');
|
||||
c.step = 'smazzata'; c.score = [22, 24]; advance(c); assert.equal(c.result.winner, 'cpu');
|
||||
assert.match(status(c), /Hanno vinto loro, 22 a 24/);
|
||||
test('si va ai 21: chi ci arriva per primo è fuori, anche a metà smazzata, e la vittoria non si perde', () => {
|
||||
const c = newTressette(3); c.pending = [[], [], [], []];
|
||||
c.base = [20, 19]; c.score = [20, 19]; c.thirds = [2, 0];
|
||||
// Una presa da un terzo porta noi a 21 (3 terzi = 1 punto): fuori subito.
|
||||
c.table = [{ who: 0, card: card('cuori', '3') }, { who: 1, card: card('cuori', '4') }, { who: 2, card: card('cuori', '5') }, { who: 3, card: card('cuori', '6') }];
|
||||
c.step = 'trick'; c.last = { winner: 0, cards: c.table.map(p => p.card) };
|
||||
assert.ok(collect(c)); assert.equal(c.step, 'result'); assert.equal(c.result.winner, 'player'); assert.deepEqual(c.score, [21, 19]);
|
||||
assert.ok(finished(c)); assert.equal(advance(c), false);
|
||||
assert.match(status(c), /Avete vinto voi, 21 a 19/);
|
||||
// Anche le accuse bastano: dette giocando, contano alla fine di quella presa.
|
||||
const d = newTressette(3); d.base = [0, 19]; d.score = [0, 19]; d.current = 1; d.table = []; d.tricks = [];
|
||||
d.pending = [[], [{ who: 1, kind: 'napoletana', suit: 'fiori', points: 3, cards: [] }], [], []];
|
||||
d.hands[1] = [card('fiori', '7'), ...d.hands[1].slice(1)];
|
||||
assert.ok(play(d, 0, 1)); assert.equal(d.score[1], 22);
|
||||
for (const seat of [2, 3, 0]) { d.current = seat; play(d, choose(observation(d, seat), 'seria').index, seat); }
|
||||
assert.equal(d.step, 'trick'); collect(d); assert.equal(d.step, 'result'); assert.equal(d.result.winner, 'cpu');
|
||||
});
|
||||
|
||||
test('partite intere deterministiche col seme; i due mazzi danno le stesse carte', () => {
|
||||
@@ -117,6 +134,26 @@ test('il socio ritorna il seme a chi ha bussato', () => {
|
||||
assert.equal(c.hands[2][m.index].suit, 'cuori'); assert.equal(c.hands[2][m.index].rank, '4');
|
||||
});
|
||||
|
||||
test('chi riceve il busso prende con la migliore; il socio non spreca il 3 su una presa già sua', () => {
|
||||
const c = newTressette(8); c.pending = [[], [], [], []]; c.current = 2;
|
||||
c.table = [{ who: 0, card: card('cuori', '4'), signal: 'busso' }, { who: 1, card: card('cuori', '5') }];
|
||||
c.hands[2] = hand([['cuori', '2'], ['cuori', '6'], ['fiori', '7']]);
|
||||
assert.equal(c.hands[2][choose(observation(c, 2), 'male').index].rank, '2', 'al busso risponde col 2');
|
||||
const d = newTressette(8); d.pending = [[], [], [], []]; d.current = 3;
|
||||
d.table = [{ who: 0, card: card('fiori', '6') }, { who: 1, card: card('fiori', '2') }, { who: 2, card: card('fiori', '4') }];
|
||||
d.hands[3] = hand([['fiori', '3'], ['fiori', '5'], ['cuori', '7']]);
|
||||
// L'avversario del posto 3: il suo socio (1) prende col 2 e lui è l'ultimo; tiene il 3 e dà il 5.
|
||||
assert.equal(d.hands[3][choose(observation(d, 3), 'male').index].rank, '5');
|
||||
});
|
||||
|
||||
test('chi vola ha finito il seme: per «A fassi male» non può più avere il 3', () => {
|
||||
const c = newTressette(8); c.pending = [[], [], [], []]; c.current = 1;
|
||||
c.tricks = [{ leader: 2, winner: 0, cards: [{ who: 2, card: card('cuori', '4'), signal: 'volo' }, { who: 3, card: card('cuori', '5') }, { who: 0, card: card('cuori', '6') }, { who: 1, card: card('cuori', '7') }] }];
|
||||
c.hands[1] = hand([['cuori', '2'], ['fiori', '4']]); c.table = [];
|
||||
const k = knowledge(observation(c, 1), true);
|
||||
assert.equal(k.could(2, card('cuori', '3')), false);
|
||||
});
|
||||
|
||||
test('taratura: Alla bona < Seria < A fassi male, contro Andrea e il socio che giocano attenti', () => {
|
||||
const runs = calibrate(60);
|
||||
assert.ok(runs[0].playerPercent > runs[1].playerPercent, JSON.stringify(runs));
|
||||
|
||||
Reference in New Issue
Block a user