feat: hand parser uses 'x' blanks instead of guessing suits/cards
Per Brian: never invent. Unknown suit -> 'x' (e.g. "Ax","Kx","4x"); fully unknown card -> "x". "AA, ace of spades" -> ["As","Ax"]; "AK on A4x" -> board ["Ax","4x","x"]. Each card's suit is independent (a hole 'As' doesn't make a board ace 'As'). Viewer renders 'x' as a muted unknown card and 'Rx' as the rank with a neutral suit dot. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
+8
-3
@@ -216,7 +216,7 @@ Schema:
|
|||||||
"game": "NLH" | "PLO" | ...,
|
"game": "NLH" | "PLO" | ...,
|
||||||
"stakes": "<e.g. 1/3, or null>",
|
"stakes": "<e.g. 1/3, or null>",
|
||||||
"hero_pos": "<UTG|UTG1|MP|LJ|HJ|CO|BTN|SB|BB, hero's position>",
|
"hero_pos": "<UTG|UTG1|MP|LJ|HJ|CO|BTN|SB|BB, hero's position>",
|
||||||
"hero_cards": ["Rs", ...], // rank+suit; suit one of s h d c; null if unknown
|
"hero_cards": ["As","Ax", ...], // rank+suit (s/h/d/c); 'x' suit if unknown e.g. "Ax"; "x" for a fully unknown card
|
||||||
"players": [ // every player mentioned, incl. hero
|
"players": [ // every player mentioned, incl. hero
|
||||||
{"pos": "<position>", "stack": <number|null>, "name": <string|null>, "cards": [".."]|null}
|
{"pos": "<position>", "stack": <number|null>, "name": <string|null>, "cards": [".."]|null}
|
||||||
],
|
],
|
||||||
@@ -230,8 +230,13 @@ Schema:
|
|||||||
}
|
}
|
||||||
|
|
||||||
Rules: infer positions and street order sensibly. Amounts are plain numbers (no $). \
|
Rules: infer positions and street order sensibly. Amounts are plain numbers (no $). \
|
||||||
Normalize cards like "Ah","Td","9s". Use null/omit for anything not stated. Stay faithful \
|
NEVER invent suits or cards. A card is rank+suit where suit is one of s/h/d/c; if the suit \
|
||||||
to what's described — do not invent action that isn't implied."""
|
wasn't stated, use 'x' for the suit (e.g. "Ax","Kx","4x"); if a whole card wasn't stated, \
|
||||||
|
use "x". Examples: "AA with the ace of spades" -> hero_cards ["As","Ax"]; "AK on an A4x \
|
||||||
|
board" -> board ["Ax","4x","x"]. Each card is independent: a suit named for one card does \
|
||||||
|
NOT apply to another — e.g. your hole "ace of spades" is a different card from a board ace \
|
||||||
|
whose suit is unstated (that board ace is "Ax", not "As"). Use null/omit for non-card \
|
||||||
|
details not stated. Stay faithful to what's described — do not invent action that isn't implied."""
|
||||||
|
|
||||||
|
|
||||||
def _safe_json(s: str) -> dict | None:
|
def _safe_json(s: str) -> dict | None:
|
||||||
|
|||||||
@@ -37,6 +37,8 @@
|
|||||||
.card .r{font-size:1rem;}
|
.card .r{font-size:1rem;}
|
||||||
.card.red{color:#c8102e;}
|
.card.red{color:#c8102e;}
|
||||||
.card.back{background:#2a3550;color:#2a3550;}
|
.card.back{background:#2a3550;color:#2a3550;}
|
||||||
|
.card.unknown{background:#2a3550;color:#7c879e;font-size:1.2rem;}
|
||||||
|
.card .nosuit{color:#9aa3b5;}
|
||||||
|
|
||||||
.seat{position:absolute;transform:translate(-50%,-50%);width:96px;text-align:center;
|
.seat{position:absolute;transform:translate(-50%,-50%);width:96px;text-align:center;
|
||||||
background:rgba(13,16,22,.85);border:1px solid var(--border);border-radius:10px;padding:5px 4px;}
|
background:rgba(13,16,22,.85);border:1px solid var(--border);border-radius:10px;padding:5px 4px;}
|
||||||
@@ -84,9 +86,12 @@
|
|||||||
|
|
||||||
function cardEl(code, sm){
|
function cardEl(code, sm){
|
||||||
if(!code) return '';
|
if(!code) return '';
|
||||||
const m = String(code).trim().match(/^(10|[2-9TJQKA])\s*([shdc])$/i);
|
const c = String(code).trim();
|
||||||
if(!m) return `<span class="card${sm?' sm':''}">${esc(code)}</span>`;
|
if(c.toLowerCase()==='x') return `<span class="card${sm?' sm':''} unknown">?</span>`;
|
||||||
|
const m = c.match(/^(10|[2-9TJQKA])\s*([shdcx])$/i);
|
||||||
|
if(!m) return `<span class="card${sm?' sm':''}">${esc(c)}</span>`;
|
||||||
const r = m[1].toUpperCase().replace('10','T'); const s = m[2].toLowerCase();
|
const r = m[1].toUpperCase().replace('10','T'); const s = m[2].toLowerCase();
|
||||||
|
if(s==='x') return `<span class="card${sm?' sm':''}"><span class="r">${r}</span><span class="nosuit">·</span></span>`;
|
||||||
return `<span class="card${sm?' sm':''}${RED.has(s)?' red':''}"><span class="r">${r}</span><span>${SUIT[s]}</span></span>`;
|
return `<span class="card${sm?' sm':''}${RED.has(s)?' red':''}"><span class="r">${r}</span><span>${SUIT[s]}</span></span>`;
|
||||||
}
|
}
|
||||||
const cards = (arr, sm) => (arr||[]).map(c=>cardEl(c,sm)).join('');
|
const cards = (arr, sm) => (arr||[]).map(c=>cardEl(c,sm)).join('');
|
||||||
|
|||||||
Reference in New Issue
Block a user