analyze_deck
Analyze Hearthstone deck codes to identify archetypes, explain gameplans, assess strengths and weaknesses, and predict matchup outcomes for strategic coaching.
Instructions
Analyze a Hearthstone deck code to classify its archetype, explain its gameplan, identify strengths and weaknesses, and predict matchup dynamics. Use this for strategic deck coaching — it combines card data with strategy knowledge.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| deck_code | Yes | Hearthstone deck code (base64 deckstring) |
Implementation Reference
- src/tools/analyze-deck.ts:96-239 (handler)The `analyzeDeck` function is the handler for the 'analyze_deck' tool. It decodes the provided deck code, queries the database for card details and archetype strategies, and returns a structured analysis of the deck.
export function analyzeDeck( db: Database.Database, input: AnalyzeDeckInputType, ): AnalyzeDeckResult { // 1. Decode the deck let decoded: { cards: Array<[number, number]>; heroes: number[]; format: number }; try { decoded = decode(input.deck_code); } catch (err) { return { success: false, message: `Invalid deck code: ${err instanceof Error ? err.message : String(err)}`, }; } // 2. Format const format = decoded.format === 1 ? 'Wild' : 'Standard'; // 3. Hero class let heroClass = 'UNKNOWN'; if (decoded.heroes.length > 0) { const heroDbfId = decoded.heroes[0]; const heroRow = db .prepare('SELECT player_class FROM cards WHERE id = ?') .get(String(heroDbfId)) as { player_class: string | null } | undefined; if (heroRow?.player_class) { heroClass = heroRow.player_class; } else if (HERO_CLASS_MAP[heroDbfId]) { heroClass = HERO_CLASS_MAP[heroDbfId]; } } // 4. Build card list and profile data const deckCards: Array<{ name: string; mana_cost: number | null; count: number }> = []; const profileCards: DeckProfile['cards'] = []; const manaCurve: Record<string, number> = {}; const typeDistribution: Record<string, number> = {}; let totalCards = 0; let totalCost = 0; let cardsWithCost = 0; for (const [dbfId, count] of decoded.cards) { const row = db .prepare('SELECT * FROM cards WHERE id = ?') .get(String(dbfId)) as CardRow | undefined; const name = row ? row.name : `Unknown Card (${dbfId})`; const manaCost = row?.mana_cost ?? null; const type = row?.type ?? null; const text = row?.text ?? null; const keywords = row?.keywords ?? null; deckCards.push({ name, mana_cost: manaCost, count }); // Add profile cards (expand by count for classification) for (let i = 0; i < count; i++) { profileCards.push({ mana_cost: manaCost, type, text, keywords }); } totalCards += count; // Mana curve const bucket = manaCurveBucket(manaCost); manaCurve[bucket] = (manaCurve[bucket] ?? 0) + count; // Type distribution const cardType = type ?? 'UNKNOWN'; typeDistribution[cardType] = (typeDistribution[cardType] ?? 0) + count; // Average cost tracking if (manaCost != null) { totalCost += manaCost * count; cardsWithCost += count; } } const avgCost = cardsWithCost > 0 ? totalCost / cardsWithCost : 0; // 5. Build DeckProfile and classify const profile: DeckProfile = { avg_cost: avgCost, cards: profileCards, total_cards: totalCards, mana_curve: manaCurve, type_distribution: typeDistribution, }; const classification = classifyArchetype(profile); // 6. Look up archetype info from strategy tables let archetypeInfo: AnalyzeDeckSuccess['archetype_info'] | undefined; const archetypeRow = db .prepare('SELECT * FROM archetypes WHERE LOWER(name) = LOWER(?)') .get(classification.archetype) as ArchetypeRow | undefined; if (archetypeRow) { archetypeInfo = { description: archetypeRow.description, gameplan: archetypeRow.gameplan, strengths: parseJson(archetypeRow.strengths), weaknesses: parseJson(archetypeRow.weaknesses), }; } // 7. Look up matchup expectations let matchups: AnalyzeDeckSuccess['matchups'] | undefined; const matchupRows = db .prepare( `SELECT archetype_a, archetype_b, favoured, key_tension FROM matchup_framework WHERE LOWER(archetype_a) = LOWER(?) OR LOWER(archetype_b) = LOWER(?)`, ) .all(classification.archetype, classification.archetype) as MatchupRow[]; if (matchupRows.length > 0) { matchups = matchupRows .filter((m) => m.archetype_a.toLowerCase() !== m.archetype_b.toLowerCase() || m.archetype_a.toLowerCase() !== classification.archetype.toLowerCase()) .map((m) => { const isA = m.archetype_a.toLowerCase() === classification.archetype.toLowerCase(); return { vs_archetype: isA ? m.archetype_b : m.archetype_a, favoured: m.favoured, key_tension: m.key_tension, }; }); } return { success: true, deck: { format, hero_class: heroClass, cards: deckCards, total_cards: totalCards, mana_curve: manaCurve, type_distribution: typeDistribution, }, classification, archetype_info: archetypeInfo, matchups: matchups && matchups.length > 0 ? matchups : undefined, }; } - src/tools/analyze-deck.ts:9-11 (schema)The Zod schema `AnalyzeDeckInput` defines the required input for the `analyze_deck` tool.
export const AnalyzeDeckInput = z.object({ deck_code: z.string().describe('Hearthstone deck code (base64 deckstring)'), }); - src/server.ts:164-174 (registration)The 'analyze_deck' tool is registered in `src/server.ts`, where it uses `AnalyzeDeckInput` for parameter validation and calls `analyzeDeck` to process the request.
// 5. analyze_deck server.tool( 'analyze_deck', 'Analyze a Hearthstone deck code to classify its archetype, explain its gameplan, identify strengths and weaknesses, and predict matchup dynamics. Use this for strategic deck coaching — it combines card data with strategy knowledge.', AnalyzeDeckInput.shape, async (params) => { try { const result = analyzeDeck(db, params); return { content: [ { type: 'text' as const, text: formatAnalyzeDeck(result) },