Progetto:BridgeShape Motore e frontend: differenze tra le versioni
| [versione verificata] | [versione verificata] |
Aggiornamento da DEAL_ENGINE_SPEC.md (LTC, semi_balanced, jolly x, casi di test) |
Aggiunto link a Smazzate di gioco |
||
| Riga 1: | Riga 1: | ||
Documentazione BridgeShape: [[Progetto:BridgeShape API|API e sintassi DSL]] · [[Progetto:BridgeShape Ricette DSL|Ricette DSL]] | Documentazione BridgeShape: [[Progetto:BridgeShape API|API e sintassi DSL]] · [[Progetto:BridgeShape Ricette DSL|Ricette DSL]] · [[Progetto:BridgeShape Smazzate di gioco|Smazzate di gioco]] | ||
= BridgeShape — Specifica del motore di smazzate e del frontend (per Play) = | = BridgeShape — Specifica del motore di smazzate e del frontend (per Play) = | ||
Versione delle 19:06, 27 ott 2026
Documentazione BridgeShape: API e sintassi DSL · Ricette DSL · Smazzate di gioco
BridgeShape — Specifica del motore di smazzate e del frontend (per Play)
Destinatario: il team/sessione di Play (generatore di smazzate e relativo frontend). Obiettivo: realizzare un motore completo che generi mani per qualsiasi scenario descritto nelle pagine di BridgePedia, e un frontend per consultare gli scenari, generare, creare e gestire smazzate.
Documenti collegati (leggere in quest'ordine):
DEAL_GENERATOR_API.md— riferimento della sintassi (DSL v1 + v2) e del JSON dell'API.- questo file — semantica normativa, architettura del motore, test di conformità, specifica del frontend, piano di consegna.
- Wiki:
Progetto:BridgeShape API; le pagine di convenzione conshape_constraints(elenco:GET /api.php?action=bridgeshape&shapeaction=list).
Fonte di verità del contratto: l'API action=bridgeshape di https://bridgepedia.it.
Se questo documento e l'API divergono vale l'API; segnalatelo a BridgePedia.
1. Contratto, versioni e compatibilità
| Elemento | Dove | Uso |
|---|---|---|
dslVersion
|
risposta di get e validate
|
oggi 2. Cambia solo con modifiche non retrocompatibili
|
scenarios[].requires
|
get, validate
|
tag delle capacità richieste dallo scenario (§1.1) |
errors
|
get, validate
|
contraddizioni semantiche: non generare |
warnings
|
get, validate
|
frammenti del DSL scartati dal parser: non generare |
descriptions
|
get, validate
|
testo leggibile per scenario, tradotto (lang=it|en|...)
|
valid
|
validate
|
1/0 |
Regole di compatibilità:
- I campi nuovi compaiono solo se usati: un motore v1 continua a funzionare sulle pagine v1.
- Campi sconosciuti: ignorarli non è permesso se compaiono in
requires. Se il motore non supporta un tag direquires, deve rifiutare lo scenario con codiceunsupported_feature(e nome del tag) e il frontend deve mostrarlo come "non ancora generabile", non nasconderlo. - Il booleano nel JSON è sempre
1/0(MediaWiki rimuove ifalse). - Tutte le chiavi di seme sono
S H D Coppure una variabile"$a".."$d".
1.1 Tag requires
| Tag | Costrutti | Impatto sul motore |
|---|---|---|
suit_cards
|
S=KJT
|
assegnazione di onori precisi |
suit_patterns
|
S~AKQ.|A...
|
alternative di mano nel seme |
vars
|
$a $b, vars
|
seme scelto a runtime, condiviso tra posizioni |
stoppers
|
stop:S
|
filtro/vincolo sulla mano |
card_presence
|
has:HQ, lacks:SK
|
carte fisse |
controls
|
aces kings queens controls kc
|
conteggi di onori |
points
|
tp dp ltc
|
punteggi derivati |
pair_points
|
pairhcp pairtp defhcp
|
vincolo sulla coppia |
compare
|
H>S, longest:
|
relazioni tra lunghezze |
shape_pattern
|
shape:5-4-x-x
|
forma ordinata |
any_not
|
any(...), not(...)
|
disgiunzioni e negazioni |
context
|
dealer vul auction contract declarer lead
|
metadati e carta d'attacco |
weight
|
weight:N
|
scelta ponderata dello scenario |
Le macro @M=H,S e quiet sono già espanse dal parser (non compaiono mai).
1.2 Endpoint consigliati lato Play
Il motore deve esporre (nomi indicativi; l'importante è la semantica):
<syntaxhighlight lang="text"> POST /api/deals/generate {
"source": { "page": "Splinter", "scenario": "1H-4C" } // oppure { "dsl": "..." }
| { "page": "Splinter" }, // scenario scelto per peso
"count": 10, // 1..100
"seed": 12345, // opzionale, riproducibilità
"fixed": { "opener": "SAK2.H.D.C", "responder": "..." }, // carte/mani già fissate (§5.6)
"lang": "it"
} → 200 { "seed":..., "deals":[ {
"scenario": "1H-4C", "index": 0,
"dealer": "opener", "vul": "none",
"hands": { "opener":"AK2.QJ53.K84.T65", "responder":"...", "opp1":"...", "opp2":"..." },
"bindings": { "$a": "H", "x:opener": "D" }, // come sono state risolte variabili e jolly
"pbn": "[Deal \"N:...\"]", "lin": "...",
"explanation": { "opener": ["♥: 5+ carte", ...], ... }, // dalle descriptions
"stats": { "attempts": 412, "ms": 38 }
} ] }
→ 422 { "code": "...", "reasons": [ {"code":"...", "position":"opp1", "detail":"..."} ] } GET /api/deals/capabilities → { "dslVersion": 2, "supports": ["suit_cards", ...] } </syntaxhighlight>
Posizioni → sedi: opener = Nord per default; il motore ruota in base a context.dealer solo
per la numerazione/PBN; i vincoli restano sempre in termini di ruoli (opener, responder,
opp1 = a sinistra dell'apertore, opp2 = a destra).
2. Definizioni normative
Il motore e il frontend devono usare esattamente queste definizioni (le descrizioni in italiano dell'API le presuppongono).
- Carte: A K Q J 10 9 8 7 6 5 4 3 2. Nei vincoli
T= 10. "Carte basse" = 8..2. - PO / HCP: A=4, K=3, Q=2, J=1.
Shcpecc. = PO nel solo seme. - Posizioni e coppie: coppia dichiarante =
opener+responder; difesa =opp1+opp2. Senso di gioco: opener → opp1 → responder → opp2 (orario). Lo stesso per l'attaccante: siede a sinistra del dichiarante (declarer= opener → attacca opp1; responder → opp2; opp1 → responder; opp2 → opener). - Forma ordinata: le 4 lunghezze in ordine decrescente (es. 5431).
- Classi di forma (possono sovrapporsi; le pagine oggi usano solo
balanced):balanced: 4333, 4432, 5332.semi_balanced: 5422, 6322.one_suiter: seme più lungo ≥ 6 e secondo ≤ 3.two_suiter: i due semi più lunghi hanno entrambi ≥ 4 carte e insieme ≥ 9 (5-4, 6-4, 5-5, ...).three_suiter: tre semi ≥ 4 (4441, 5440, 4450...).any: nessun vincolo. Se la vostra implementazione attuale differisce, allineatela a questa o segnalate la differenza.
shape_pattern(54xx): la forma ordinata deve corrispondere cifra per cifra;x= qualsiasi.longest:H: la lunghezza di H è ≥ di ogni altro seme (pari merito ammesso).- Confronti
A op B: sulle lunghezze dei due semi nella stessa mano;==uguali. - Controlli: A=2, K=1 (le dame non contano).
controls:6+somma sulla mano. - Carte chiave per l'atout T (
kc:T): numero di assi (0-4) + 1 se possiede il Re di T. Valori 0-5. La Dama di atout si esprime conhas:TQ. - Fermata nel seme X (
stop:X): possiede almeno una tra: A; Kx (Re con ≥ 2 carte nel seme); Qxx (Dama con ≥ 3); Jxxx (Fante con ≥ 4).nostop:X= nessuna di queste. - Punti totali
tp: PO + (per ogni seme,max(0, lunghezza − 4)). - Punti distribuzione
dp: PO + 3 per ogni chicane + 2 per ogni singolo + 1 per ogni doubleton. - Perdenti
ltc(Losing Trick Count classico): per ogni seme conncarte,m = min(n,3); perdenti del seme =m − [A] − [K e n≥2] − [Q e n≥3]; somma sui 4 semi (seme vuoto = 0). Tabella di controllo: x=1, A=0, K=1, Q=1; xx=2, Ax=1, Kx=1, Qx=2, AK=0, AQ=1, KQ=1; AKQ=0, AKx=1, AQx=1, KQx=1, Axx=2, Kxx=2, Qxx=2, xxx=3. (Correzione: la formula precedentem − #A,K,Qcontava anche K e Q secchi o Q doppia.) S=KJT(suit_cards): tra A K Q J 10 9 possiede esattamente quelle elencate; 8..2 liberi. Stringa vuota = nessuna carta alta. Gli onori elencati sono esclusi dalle altre mani solo per quel che riguarda la proprietà: ogni carta ha un unico proprietario.S~...(suit_patterns): una sola alternativa (scelta a caso, uniformemente tra quelle compatibili con gli altri vincoli) descrive tutta la mano in quel seme:cards+ tralow_minelow_maxcarte basse (low_max: null= illimitato, ma ≤ 13 − len(cards)).x:(jolly di posizione): un seme scelto a caso tra quelli non vincolati esplicitamente in quella posizione. Dentro una foglia diany()/not()il jolly vede solo i semi nominati nella foglia; un seme nominato soltanto infit, confronti olongest:non è escluso dax;xhcp:si riferisce allo stesso seme. Il jolly non è condiviso con altre posizioni.- Variabili
$a..$d: a inizio generazione ogni variabile usata riceve un seme dal proprio dominio (vars, default tutti e quattro). Variabili diverse hanno semi diversi; una variabile non dichiarata ha dominio completo. Una variabile può coincidere con un seme nominato esplicitamente ($aeH): se non è voluto, restringere il dominio ($a=SD). La scelta è uniforme tra le assegnazioni che rendono lo scenario soddisfacibile. fit: somma delle lunghezze dei due compagni nel seme (o in qualunque seme del tipomajor/minor/any, a scelta del motore, uniformemente tra i semi che soddisfano il vincolo).any(A,B): la mano soddisfa almeno una alternativa.not(A,B): non ne soddisfa nessuna. Più gruppi → AND. DentroA,Bvalgono gli stessi campi di una posizione (senzaany/not/fit).pair_hcp.declarer= PO(opener)+PO(responder);defense= PO(opp1)+PO(opp2).pair_tp: sommatp.- Posizioni non nominate: ricevono le carte rimanenti a caso (nessun vincolo); non applicare
quietimplicito. weight: probabilità relativa di scelta dello scenario quando non è scelto dall'utente (default 1). Non influenza la generazione dentro lo scenario.context: metadati.dealerevul(us= coppia dichiarante) vanno riportati nell'output (PBN/LIN) e mostrati.auctionè la sequenza da mostrare/verificare (notazione BridgeCards:P,X,XX,1NT...).contract/declarer/lead: vedi §5.7.
3. Architettura consigliata del motore
Pipeline per ogni mano richiesta:
<syntaxhighlight lang="text"> parse risposta API → controllo requires/errors/warnings
→ scelta scenario (utente | peso) → ASSEGNAZIONE SIMBOLICA : variabili $a.., jolly x:, fit, alternative any()/S~, pattern di forma → MATRICE DELLE LUNGHEZZE : 4 posizioni × 4 semi (somme 13 per riga e per colonna) → ASSEGNAZIONE DELLE CARTE : carte fissate/vincolate, poi resto casuale → RIPARAZIONE PUNTI : scambi mirati per entrare negli intervalli PO/tp/dp/ltc/controlli → VERIFICA FINALE : valutazione indipendente di TUTTI i vincoli sulla smazzata completa → output + spiegazione
</syntaxhighlight>
Punti chiave:
- Verifica finale indipendente (il "giudice"): una funzione pura
satisfies(deal, scenario, bindings)che valuta ogni vincolo dalle definizioni di §2. Ogni smazzata emessa deve passarla. Questa funzione è anche la base dei test e del pulsante "verifica" del frontend. - Costruzione, non solo scarto. Il rejection sampling puro non regge scenari stretti (es. Gran rever nel Multirever,
quietcon coppia 25+ PO). Costruire prima la matrice delle lunghezze con propagazione dei vincoli (backtracking con limiti per riga/colonna), poi assegnare le carte onore per posizione secondosuit_cards/suit_patterns/has/lacks/aces..., infine le basse. - Riparazione PO: dopo l'assegnazione, se i PO (o
tp,dp,ltc, controlli,pair_*) sono fuori intervallo, scambiare due carte tra due mani preservando lunghezze e vincoli rigidi (carte fissate, pattern). Ricerca locale con budget; poi nuovo tentativo dall'inizio. - Uniformità: l'obiettivo è una distribuzione quasi uniforme tra le smazzate che soddisfano lo scenario. Le euristiche di costruzione introducono distorsioni: misuratele (§7.3) e non dichiarate "uniformi" se non lo sono.
- Budget e fallimenti: limite di tempo (oggi 2,5 s CPU/mano), massimo tentativi, e diagnosi. Su fallimento restituire 422 con i
reasonsdi §6, mai una smazzata che viola i vincoli. - Riproducibilità: stesso
seed+ stessa versione del DSL → stessa smazzata. Salvare nel recordseed,dslVersion,source.page,reviddella pagina se disponibile. - Concorrenza e cache: cache del JSON dell'API per pagina con TTL breve (60 s) e rivalidazione sulla
list; mai servire DSL non validato.
3.1 Ordine di risoluzione dei vincoli
- Variabili
$a.., jollyx:,fit(decidono quali semi). - Alternative: scegliere un ramo per ogni
any()e ogniS~(escludendo i rami impossibili con i vincoli già noti); applicarenot()come vincoli di esclusione. - Lunghezze (
suits,compare,longest,shape,shape_pattern,fit). - Carte precise (
suit_cards,suit_patterns,cards_held/not_held,lead). - Conteggi (
aces,kings,queens,controls,keycards,suit_hcp,hcp). - Punteggi derivati (
tp,dp,ltc,pair_*) estoppers. - Verifica finale.
Un vincolo è "rigido" se riguarda carte/lunghezze fissate (1-4); "morbido" se si ripara per scambio (5-6).
4. Semantica delle combinazioni delicate
quietè già espanso insuits,suit_hcp,hcp: nessun trattamento speciale (il campoquiet: 1serve solo alla descrizione). Una difesa quiet riduce il margine PO per la coppia dichiarante: verificare la compatibilità prima di costruire (suit_minimums_exceed_hcp_max...).S=.../S~...+S:N+Shcp: devono essere coerenti; l'API segnala le contraddizioni evidenti.- Una carta (
has:HQ) può comparire in una sola posizione; due posizioni con la stessa carta sono un errore di validazione, non un caso da risolvere a caso. any()dentro una posizione con variabili: le variabili si legano prima, poi si sceglie il ramo.not()conS~: escludere dall'insieme di alternative, non solo filtrare a posteriori.longest:ecomparevalgono sulle lunghezze finali (dopo il bind delle variabili).context.lead(SK): la carta deve stare nella mano dell'attaccante (§2) e quella mano deve soddisfare i suoi vincoli (es. se haS=KJT,lead:SJè coerente,lead:SQno).
Chiarimenti (concordati con Play)
context.auction: la sequenza parte dal mazziere (dealer); il primo token è la sua chiamata. Sedealermanca, l'asta è solo descrittiva e non si verifica nulla. Nella v2 l'asta econtractsono informativi: il motore non deve ricavarne vincoli sulle mani.declarer: non deve discendere dall'asta (non verificata). Serve a stabilire chi attacca (vedi §2) e quindi a validarelead.errors: array di stringhe"<etichetta scenario o 'scenario #N'>: <messaggio in inglese>", senza codici né struttura. Il motore li riporta così come sono (codice propriodsl_errors, §6). Un formato strutturato (code,scenario,position) è una possibile evoluzione: lo si introdurrebbe come campo nuovoerrorDetails, senza toccareerrors.descriptions: oggi un elemento per scenario conpositions(testo per posizione) econtext; non esiste un id per singolo vincolo. Se il frontend lo richiede, si aggiungerà un campo additivo (da concordare, §11).- «Uniforme» (variabili, jolly,
fit): tra le assegnazioni di semi che rendono lo scenario soddisfacibile, ciascuna ha uguale probabilità (a meno di tolleranza statistica nei test: ±5 % su 1000 estrazioni per due valori, vedi caso 3). Non implica uniformità sulle carte o sulle mani.
5. Funzionalità del motore (elenco completo da realizzare)
5.1 Core (parità v1) — già in produzione, da conservare
Lunghezze, PO totali/per seme, x:, shape:, fit, suit_cards, suit_patterns, quiet
(espanso), 422 con ragioni, tetto 2,5 s.
5.2 Nuove funzioni DSL v2
Tutte le righe di §1.1. Priorità di consegna in §9.
5.3 Mani multiple e serie
count ≤ 100 per richiesta; opzione distinct: true (nessuna mano duplicata nella serie);
opzione balance: "round_robin" | "weighted" per distribuire gli scenari della stessa convenzione.
5.4 Spiegazione per mano
Per ogni smazzata: per posizione, elenco dei vincoli con esito (✓) e valore effettivo
("♥: 5 carte, richiesto 5+"), e i binding ($a = ♥, x di opener = ♦). Serve al frontend.
5.5 Verifica di una smazzata data
POST /api/deals/check con quattro mani e una source → elenco di vincoli soddisfatti/violati.
Usa lo stesso giudice del §3. Serve a: smazzate inserite a mano, correzione in aula, test.
5.6 Mani parzialmente fissate (fixed)
Accettare mani complete o parziali ("opener": "SAK2.", o carte singole) e completare il resto
rispettando lo scenario. Se impossibile → 422 fixed_cards_conflict.
5.7 Contesto di gioco della carta
contract, declarer, lead: il motore garantisce che la carta d'attacco sia nella mano giusta e
fornisce nel risultato play: { "contract":"4H", "declarer":"responder", "leader":"opp2", "lead":"SK" }.
(Il gioco successivo, oltre la prima carta, non è nel DSL: per Segnali e Attacchi la prima carta e le
mani bastano a mostrare la situazione.)
5.8 Statistiche
Per scenario: tasso di successo, tentativi medi, p95 ms, codici di fallimento. Esposte in
GET /api/deals/stats e inviate a BridgePedia (§8.5) per tarare i vincoli.
6. Codici di errore (422 e simili)
Già in uso: exact_cards_always_conflict, generation_time_limit, suit_cards_below_hcp_min,
suit_minimums_exceed_hcp_max, suit_cards_exceed_hcp_max. Da aggiungere:
| Codice | Quando |
|---|---|
unsupported_feature
|
lo scenario richiede un tag non supportato (detail: il tag)
|
dsl_errors
|
l'API ha restituito errors o warnings (riportarli)
|
variable_unsatisfiable
|
nessuna assegnazione dei semi variabili rende lo scenario possibile |
fixed_cards_conflict
|
fixed contraddice lo scenario o carte duplicate
|
pair_points_unreachable
|
pairhcp/pairtp incompatibili con i limiti per posizione
|
lead_conflict
|
lead incompatibile con la mano dell'attaccante
|
no_branch_left
|
any()/S~/not() eliminano tutti i rami
|
shape_unreachable
|
forma/lunghezze incompatibili con 13 carte per mano e per seme |
invalid_request
|
parametri non validi (count, seed...) |
Ogni 422 porta reasons: [{code, position?, detail}] leggibili dal frontend.
7. Test di conformità e qualità
7.1 Invarianti (property test, ≥ 10.000 smazzate per scenario del wiki)
- 52 carte distinte; 13 per mano; nessun duplicato.
satisfies()vero per ogni smazzata emessa (il giudice non deve condividere codice con il generatore).- Stesso seed → stesso risultato.
7.2 Casi minimi per costrutto (la DSL → cosa deve valere)
| # | DSL | Asserzione |
|---|---|---|
| 1 | opener S:5+ hcp:12-21
|
♠ ≥ 5, PO in intervallo |
| 2 | @M=H,S opener ${M}:5+
|
due scenari generabili (H, S)
|
| 3 | $a=M opener $a:5+; responder $a:3+
|
in ogni mano: un nobile ≥5 in opener, lo stesso seme ≥3 in responder; entrambi i nobili compaiono su 1000 mani |
| 4 | $a=M $b=m opener $a:5+ $b:4+
|
$a nobile, $b minore, mai lo stesso seme |
| 5 | opener stop:S su 1000 mani
|
tutte le mani hanno A, Kx, Qxx o Jxxx a ♠ |
| 6 | opener nostop:S S:3+
|
nessuna mano con A, né Kx, Qxx o Jxxx a ♠ (con 3 carte: né A, né K, né Q) |
| 7 | opener aces:2 kc:H3
|
2 assi; assi + K♥ = 3 (kc:H4 con aces:2 è impossibile: max 2+1)
|
| 8 | opener has:HQ lacks:SK
|
Q♥ presente, K♠ assente |
| 9 | opener tp:20-22
|
tp corretto con la definizione di §2
|
| 10 | opener ltc:6-7
|
LTC con la definizione di §2 |
| 11 | opener H>S e opener H>=S longest:H
|
confronti rispettati; longest con pari merito
|
| 12 | opener shape:5-4-x-x
|
5 e 4 come due semi più lunghi in ordine; gli altri due sommano 4 |
| 13 | opener shape:semi_balanced
|
solo 5422 e 6322 |
| 14 | opener any(S:5+, H:5+)
|
almeno un nobile ≥ 5 |
| 15 | opener not(S:4+, H:4+)
|
nessun nobile ≥ 4 |
| 16 | opener any(S:4+ hcp:12+, H:4+)
|
rami composti |
| 17 | pairhcp:25+ ... opp1 quiet; opp2 quiet
|
coppia ≥ 25, avversari entro i limiti quiet |
| 18 | weight:1 ... // weight:3 ...
|
1000 estrazioni ~ 25%/75% (± tolleranza) |
| 19 | dealer:opp1 vul:both
|
output con dealer/vul corretti e PBN ruotato |
| 20 | declarer:responder lead:SJ opp2 S=KJT
|
J♠ in opp2; con lead:SQ → 422 lead_conflict
|
| 21 | fixed con Q♥ in opener
|
opener ha Q♥ e rispetta lo scenario |
| 22 | scenario impossibile (S=AK Shcp:0-2)
|
422 con ragione |
| 23 | scenario con unsupported simulato
|
422 unsupported_feature
|
Aggiungere come test di regressione tutti gli scenari reali delle pagine del wiki
(shapeaction=list → get): per ciascuno ≥ 1000 smazzate valide entro il budget, oppure una
diagnosi documentata. Gli scenari più duri oggi: Multirever (Gran rever, 20 scenari) e
Segnale di Smith (20 scenari con suit_cards).
7.3 Qualità statistica
Per ogni scenario del wiki misurare su 5000 mani: distribuzione delle lunghezze e dei PO nei limiti consentiti, tasso di riuscita al primo tentativo, tempo p50/p95. Segnalare distorsioni evidenti (es. la posizione A prende sempre i PO alti).
7.4 Prestazioni
Obiettivo: p95 < 300 ms per mano sugli scenari comuni; < 2,5 s sul peggiore. Se non si rispetta, non allargare i vincoli: segnalare lo scenario a BridgePedia (§8.5) che può rivederlo.
8. Frontend di Play
Il frontend deve permettere di consultare, generare, creare e gestire smazzate.
Lingua: italiano, con i18n predisposta (en, fr, es, de). Tutti i testi dei vincoli vengono
dall'API (descriptions, parametro lang): non riscriverli.
8.1 Catalogo delle convenzioni
- Elenco da
shapeaction=list(con vincoli) elistall(tutte, conhasShape). - Per ogni voce: titolo, numero di scenari, link alla pagina del wiki, stato: generabile, parzialmente generabile (alcuni scenari con
requiresnon supportato), non generabile. - Ricerca testuale; filtri per tipologia/sistema se esposti; badge "da verificare" per le traduzioni non verificate.
- Le 27 convenzioni senza vincoli compaiono come "scenari in arrivo" con link al wiki.
8.2 Visualizzatore di scenario
- Tabella a colonne per posizione (come la tabella del wiki): etichetta scenario, frasi di
descriptions[i].positions,positionLabels(rispettare i ruoli personalizzati, es. "Attaccante"),fit,context. - Semi ♥ ♦ in rosso. Mostrare
requirescome chip (tooltip con spiegazione). - Pulsante "Mostra DSL" (testo
raw) e "Apri la pagina nel wiki".
8.3 Generatore
- Scelta convenzione → scenario (singolo, "a caso", "tutti a rotazione", pesato) → quantità (1-100) → opzioni (seed, mani distinte, nascondi avversari).
- Risultato: schede smazzata con 4 mani (formato BridgeCards: ♠♥♦♣, bordi, dealer, vulnerabilità), etichetta scenario, pannello "perché questa mano": per posizione le frasi di
explanationcon spunta, binding ($a = ♥), PO/lunghezze effettive. - Azioni per smazzata: rigenera, "blocca questa mano e rigenera le altre" (usa
fixed), copia link con seed, esporta PBN/LIN/immagine, aggiungi alla raccolta. - Se la licita
auctionè presente: mostrarla con<bidding>(stile BridgeCards) o nascosta per esercizio ("indovina la risposta"). - Gestione 422: messaggio per codice (§6) con suggerimento ("lo scenario è impossibile perché..."). Per
unsupported_feature: spiegare quale capacità manca.
8.4 Editor / creazione di scenari
Due modalità sincronizzate:
- Modulo guidato per posizione (Apertore, Compagno, Avv. sinistro, Avv. destro):
- lunghezze per seme (slider min-max), PO totali e per seme, forma (classi + schema
5-4-x-x); - griglia carte per seme (A K Q J 10 9 + "basse") con stati deve avere / non deve avere / indifferente che produce
S=...; costruttore di pattern perS~con anteprima; - interruttori: fermata (per seme), assi/re/dame/controlli, carte chiave con atout,
tp/dp/ltc, confronti tra semi,any(...)/not(...)come gruppi aggiungibili; - variabili di seme
$a..$dcon dominio (nobili/minori/qualsiasi); - contesto: dealer, vulnerabilità, licita, contratto, attacco, peso;
- avversari: pulsante quiet (e
quiet:max); - macro: "ripeti per ogni nobile / minore / seme" genera
@M=....
- lunghezze per seme (slider min-max), PO totali e per seme, forma (classi + schema
- Editor testuale del DSL con evidenziazione, completamento e validazione live: chiama
shapeaction=validate(debounce 400 ms) e mostraerrors,warnings,descriptionserequires(con il supporto del motore). Le due modalità si convertono a vicenda (modulo → DSL è obbligatorio; DSL → modulo almeno per i costrutti elementari, il resto resta testuale).
- Pulsante "Prova": genera 5 mani di test dallo scenario in modifica e mostra tempi e tassi di riuscita.
- Salvataggio come bozza personale in Play (non scrive sul wiki). Pulsante "Copia per BridgePedia" produce la riga
shape_constraintsda incollare nella pagina (gli editor del wiki fanno il resto). - Libreria di modelli presi dalle convenzioni del wiki ("parti da Landy").
8.5 Retroazione verso BridgePedia
- Pulsante "Segnala scenario problematico" (lento / troppo raro / 422 / distribuzione strana) che invia: pagina, scenario,
dslVersion, codice errore, statistiche (§5.8) al canale concordato (sessione/issue). Nessuna scrittura diretta sul wiki. - Report periodico automatico delle statistiche di generazione per scenario.
8.6 Smazzate manuali
- Compositore: assegnare le 52 carte alle quattro mani con trascinamento o digitazione (
AK2.QJ5.K84.T65), controllo duplicati, completamento casuale delle carte mancanti (opzionalmente rispettando uno scenario: usafixed). - Pulsante "Verifica rispetto a uno scenario" (§5.5) con l'elenco dei vincoli soddisfatti e violati.
- Importa/esporta PBN, LIN, testo semplice.
8.7 Gestione delle smazzate
- Raccolte ("mazzi di esercizio"): nome, descrizione, convenzione, tag; ordinamento; duplicati evitati.
- Ricerca per convenzione, scenario, tag, data; filtri per vulnerabilità, dealer.
- Metadati salvati:
seed,source.page, scenario,dslVersion,revid, data, autore. - Note personali per smazzata; stampa di una raccolta (fogli A4 con 4 o 6 smazzate per pagina, versione "solo mano dell'apertore" per esercizio).
- Condivisione: link con seed/raccolta, permessi (privato, gruppo, pubblico) secondo il modello utenti di Play. Esportazione in blocco (PBN).
- Modalità "esercizio di licita": mostra le mani di un lato, l'utente inserisce la licita, il frontend confronta con
context.auctionse presente.
8.8 Requisiti trasversali
- Mobile first; tastiera accessibile; semi anche come lettere per daltonici.
- Nessuna dipendenza dal wiki per il rendering delle carte (usare componenti propri; stile coerente con BridgeCards).
- Tempi: la generazione deve mostrare avanzamento e poter essere annullata.
- Tracciare (analytics interni) tempi, errori e scenari più usati.
- Testo dei vincoli sempre da
descriptionsconlangcoerente con la lingua dell'interfaccia.
9. Piano di consegna consigliato
| Fase | Contenuto | Esito atteso |
|---|---|---|
| P0 — compatibilità (subito) | leggere dslVersion, requires, errors, warnings; esporre /capabilities; rifiutare con unsupported_feature; giudice satisfies() per v1
|
nessuna smazzata errata con le pagine nuove |
| P1 — core v2 | macro (nessun lavoro, già espanse), weight, context, shape_pattern, classi nuove, compare/longest, any/not, pair_*
|
scenari per Landy/Cappelletti/DONT/Smolen con forme e alternative |
| P2 — variabili e carte | vars condivise tra posizioni, has/lacks, stoppers, aces/kings/queens/controls/kc
|
Michaels, Sputnik, Lebensohl, Blackwood/RKCB, Exclusion |
| P3 — punteggi | tp, dp, ltc
|
sistemi a forza (Fiori forte, 2♣ forte, Gazzilli) |
| P4 — frontend lettura | catalogo, visualizzatore, generatore con spiegazioni | tutti possono provare le convenzioni |
| P5 — frontend creazione | editor guidato + testuale con validazione live, "Prova", bozze | gli editor creano e collaudano scenari senza il wiki |
| P6 — gestione | raccolte, smazzate manuali, check, fixed, esportazioni, esercizi di licita
|
uso didattico completo |
| P7 — qualità | suite di conformità (§7), statistiche, report verso BridgePedia | motore misurabile |
Ogni fase deve chiudersi con i test di §7 per i costrutti introdotti. BridgePedia estende le
pagine del wiki man mano che i tag diventano disponibili: comunicate a ogni fase la lista dei tag supportati (/capabilities) così il wiki passa dalle approssimazioni (pattern S~) ai
costrutti nativi solo quando il motore li regge.
10. Cosa fa BridgePedia (per non sovrapporsi)
- Mantiene il DSL, il parser, le descrizioni e l'API; aggiunge costrutti su richiesta motivata.
- Scrive e tiene aggiornati gli scenari nelle pagine delle convenzioni; le 27 mancanti saranno coperte via via con i costrutti v2.
- Fornisce il catalogo di ricette (come descrivere Landy, Blackwood, un attacco sotto onore...).
- Riceve da Play le segnalazioni di §8.5 e rivede i vincoli troppo duri.
11. Decisioni aperte (da concordare con Play)
- Definizione definitiva delle classi di forma (§2) rispetto a quanto già implementato.
- Formato di
explanation(testo semplice vs struttura con esito per vincolo). - Modello di persistenza e permessi delle raccolte (utenti Play).
- Canale per le segnalazioni verso BridgePedia (§8.5).
- Se
fixeddeve accettare anche vincoli aggiuntivi temporanei (override locali dello scenario).