Deck builder: cost tiles for unowned cards and cards in other decks

Idea and Building decks get two more Deck analysis tiles: what the copies
you don't own would cost, and what the owned copies other building/built
decks are holding are worth. Both count copies, not cards.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-28 22:03:45 -05:00
parent 04dc4f6e7b
commit 8a69ca9f73
2 changed files with 20 additions and 3 deletions

View File

@@ -6,6 +6,10 @@ import { COLORS, Deck, DeckEntry, isPhysical, legalStatusFor, Partner } from "./
/** Copies of a deck card you'd need to acquire to cover the deck. */
export const shortBy = (e: DeckEntry) => Math.max(0, e.quantity - e.quantity_owned);
/** Owned copies of a deck card you can't use because other building/built
* decks claim them. */
export const claimedElsewhere = (e: DeckEntry) => Math.max(0, Math.min(e.quantity, e.quantity_owned) - e.quantity_spare);
export interface DeckStats {
totalCards: number;
uniqueCards: number;
@@ -14,6 +18,10 @@ export interface DeckStats {
/** USD for every copy in the deck, commander included; cards without a
* known price count as $0. */
totalCost: number;
/** USD for the copies you'd need to buy (see `shortBy`). */
unownedCost: number;
/** USD for the owned copies other decks are holding (see `claimedElsewhere`). */
elsewhereCost: number;
curve: {
label: string;
count: number;
@@ -102,9 +110,10 @@ export function computeDeckStats(contents: DeckEntry[]): DeckStats {
}
// Unlike the rest, cost counts the commander: it's a card you have to buy.
const totalCost = contents
.filter((e) => !e.is_maybeboard)
.reduce((sum, e) => sum + e.price_usd * e.quantity, 0);
const mainboard = contents.filter((e) => !e.is_maybeboard);
const totalCost = mainboard.reduce((sum, e) => sum + e.price_usd * e.quantity, 0);
const unownedCost = mainboard.reduce((sum, e) => sum + e.price_usd * shortBy(e), 0);
const elsewhereCost = mainboard.reduce((sum, e) => sum + e.price_usd * claimedElsewhere(e), 0);
return {
totalCards,
@@ -112,6 +121,8 @@ export function computeDeckStats(contents: DeckEntry[]): DeckStats {
landCount,
avgManaValue,
totalCost,
unownedCost,
elsewhereCost,
curve,
colorCounts,
colorlessCount,

View File

@@ -1299,6 +1299,12 @@ function DeckBuilder({
<StatTile value={deckStats.landCount} label="lands" />
<StatTile value={deckStats.avgManaValue.toFixed(2)} label="avg MV" />
<StatTile value={formatCost(deckStats.totalCost)} label="cost" />
{(deck.status === "idea" || deck.status === "building") && (
<>
<StatTile value={formatCost(deckStats.unownedCost)} label="not owned" />
<StatTile value={formatCost(deckStats.elsewhereCost)} label="in other decks" />
</>
)}
</div>
<div className="deck-stats-body">
<div className="deck-stats-numbers">