Veggerby.Boards.DeckBuilding 0.1.0-prerelease0212

This is a prerelease version of Veggerby.Boards.DeckBuilding.
dotnet add package Veggerby.Boards.DeckBuilding --version 0.1.0-prerelease0212
                    
NuGet\Install-Package Veggerby.Boards.DeckBuilding -Version 0.1.0-prerelease0212
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Veggerby.Boards.DeckBuilding" Version="0.1.0-prerelease0212" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Veggerby.Boards.DeckBuilding" Version="0.1.0-prerelease0212" />
                    
Directory.Packages.props
<PackageReference Include="Veggerby.Boards.DeckBuilding" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Veggerby.Boards.DeckBuilding --version 0.1.0-prerelease0212
                    
#r "nuget: Veggerby.Boards.DeckBuilding, 0.1.0-prerelease0212"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Veggerby.Boards.DeckBuilding@0.1.0-prerelease0212
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Veggerby.Boards.DeckBuilding&version=0.1.0-prerelease0212&prerelease
                    
Install as a Cake Addin
#tool nuget:?package=Veggerby.Boards.DeckBuilding&version=0.1.0-prerelease0212&prerelease
                    
Install as a Cake Tool

Veggerby.Boards.DeckBuilding

Deck-building core module built on Veggerby.Boards and Veggerby.Boards.Cards providing deterministic supply management, player zones (deck/hand/discard/in-play), and phase-based gameplay foundation.

Depends on Veggerby.Boards and Veggerby.Boards.Cards. Use when building deck-building games like Dominion, Ascension, or Star Realms.

Install

Package publishes with the rest of the suite. Until then, reference the project directly.

Overview

This module provides a deterministic foundation for deck-building games with:

  • CardDefinition: Metadata artifacts (name, types, cost, victory points)
  • Player Zones: Immutable pile management (Deck, Hand, Discard, InPlay)
  • Deterministic Shuffles: Seeded RNG for reproducible gameplay
  • Phase Structure: Setup → Action → Buy → Cleanup
  • Supply Management: Centralized card pool with depletion tracking
  • Scoring & Termination: Victory point computation and game-end detection

Quick Start

using Veggerby.Boards.DeckBuilding;

// Create a deck-building game
var builder = new DeckBuildingGameBuilder();
var progress = builder.Compile();

// Initialize a player's deck
var player = progress.Game.GetPlayer("player-1");
var deck = progress.Game.GetArtifact<Deck>("deck-1");

var piles = new Dictionary<string, IList<Card>>
{
    [DeckBuildingGameBuilder.Piles.Draw] = new List<Card>(),
    [DeckBuildingGameBuilder.Piles.Discard] = new List<Card>(),
    [DeckBuildingGameBuilder.Piles.Hand] = new List<Card>(),
    [DeckBuildingGameBuilder.Piles.InPlay] = new List<Card>(),
};
var supply = new Dictionary<string, int> { ["copper"] = 7, ["estate"] = 3 };

progress = progress.HandleEvent(new CreateDeckEvent(deck, piles, supply));

// Draw cards (with automatic reshuffle when deck empty)
progress = progress.HandleEvent(new DrawWithReshuffleEvent(deck, count: 5));

// Gain a card from supply
progress = progress.HandleEvent(new GainFromSupplyEvent(
    player, deck, "copper", DeckBuildingGameBuilder.Piles.Discard));

// Trash cards from hand
progress = progress.HandleEvent(new TrashFromHandEvent(deck, cardsToTrash));

// End turn cleanup
progress = progress.HandleEvent(new CleanupToDiscardEvent(deck));

Key Concepts

Phases

Phase Purpose Events
Setup Initialize deck and supply CreateDeckEvent
Action Draw cards and trash DrawWithReshuffleEvent, TrashFromHandEvent
Buy Gain cards from supply GainFromSupplyEvent
Cleanup Move cards to discard, compute scores, end game CleanupToDiscardEvent, ComputeScoresEvent, EndGameEvent

Events & Mutators

Event Mutator Description
RegisterCardDefinitionEvent RegisterCardDefinitionStateMutator Register card metadata (name, types, cost, VP)
CreateDeckEvent CreateDeckStateMutator Initialize player zones and supply
GainFromSupplyEvent GainFromSupplyStateMutator Move card from supply to player pile, decrement supply
DrawWithReshuffleEvent DrawWithReshuffleStateMutator Draw cards, reshuffle discard if needed
TrashFromHandEvent TrashFromHandStateMutator Remove cards from hand (permanent)
CleanupToDiscardEvent CleanupToDiscardStateMutator Move Hand + InPlay to Discard
ComputeScoresEvent ComputeScoresStateMutator Calculate victory points per player
EndGameEvent EndGameStateMutator Mark game as ended

Zones (Player Piles)

Each player has four standard piles:

  • Draw: Cards to be drawn
  • Hand: Cards currently available for play
  • InPlay: Cards played this turn
  • Discard: Used cards awaiting reshuffle

All pile operations are immutable; mutators return new state snapshots.

Deterministic Shuffles

Shuffles use GameState.Random with seeded RNG:

var builder = new DeckBuildingGameBuilder();
builder.WithSeed(12345);  // Reproducible shuffle order
var progress = builder.Compile();

Same seed → same shuffle sequence across all runs.

Supply Management

The supply is a shared pool of available cards:

  • Tracked in DeckSupplyStats for O(1) empty pile detection
  • Decremented on GainFromSupplyEvent
  • Used for game-end trigger (see below)

Testing

Run the module tests:

cd test/Veggerby.Boards.Tests
dotnet test --filter "FullyQualifiedName~DeckBuilding"

Test Coverage:

  • Deck initialization and supply setup
  • Gain from supply (happy path and insufficient supply)
  • Draw with automatic reshuffle (determinism verified)
  • Trash validation (card presence in hand)
  • Cleanup behavior (all cards moved to discard)
  • Scoring computation (victory point aggregation)
  • End-game trigger conditions
  • Structural invariants (phase ordering, event presence)

Game-End Trigger

Configure supply depletion trigger:

builder.WithEndTrigger(new DeckBuildingEndTriggerOptions(
  emptySupplyPilesThreshold: 3,                    // optional > 0 threshold
  keySupplyPileIds: new[]{"province", "colony"}   // optional specific key piles that must all be empty
));

Validation rule (enforced in constructor): at least one of the following must be configured:

  1. emptySupplyPilesThreshold > 0
  2. A non-empty keySupplyPileIds collection

If neither is provided, an ArgumentException is thrown. Negative thresholds throw ArgumentOutOfRangeException.

At runtime the EndGameEventCondition requires scores to have been computed (via a preceding ComputeScoresEvent) before a depletion-triggered end may validate; otherwise the end event is ignored until scoring occurs.

Error Modes

Gain From Supply Failures

GainFromSupplyEventCondition returns Fail (raising InvalidGameEventException) with these reasons:

  • Unknown pile: Target pile id not present in the deck state
  • Insufficient supply: Supply dictionary does not contain the card id or its count is zero
  • Unknown card id: Card artifact not registered in the game even though supply references it

The exception message includes the failing reason (e.g., Invalid game event GainFromSupplyEvent: Unknown pile).

Known Limitations

  • Card Effects: No action card effects implemented (beyond basic zone transitions)
  • Attack/Reaction: Interaction between players not modeled
  • Duration Cards: Multi-turn effect persistence not supported
  • Cost Reduction: Dynamic pricing not implemented
  • Benchmarks: Partial coverage only (shuffle, gain, condition gating)

Extending This Module

Common extension scenarios:

Adding Action Cards

public sealed record PlayActionEvent(Deck Deck, Card ActionCard) : IGameEvent;

public sealed class PlayActionStateMutator : IStateMutator<PlayActionEvent>
{
    public GameState MutateState(GameEngine engine, GameState state, PlayActionEvent @event)
    {
        // Move card from Hand to InPlay
        // Apply card-specific effects (draw, trash, coins, etc.)
    }
}

Implementing Card Effects

public interface ICardEffect
{
    GameState Apply(GameEngine engine, GameState state, Deck deck);
}

public sealed class DrawCardsEffect : ICardEffect
{
    private readonly int _count;
    
    public GameState Apply(GameEngine engine, GameState state, Deck deck)
    {
        // Execute draw logic
    }
}

Custom End-Game Triggers

public sealed class VictoryPointThresholdCondition : IGameStateCondition
{
    private readonly int _threshold;
    
    public ConditionResponse Evaluate(Game game, GameState state)
    {
        // Check if any player has reached VP threshold
    }
}

References

Versioning

Semantic versioning aligned with repository releases. Breaking event or rule changes bump MAJOR.

Contributing

Open issues & PRs at https://github.com/veggerby/Veggerby.Boards. Follow contributor guidelines.

License

MIT License. See root LICENSE.

Product Compatible and additional computed target framework versions.
.NET net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.1.0-prerelease0212 78 4/13/2026
0.1.0-prerelease0211 79 2/8/2026
0.1.0-prerelease0210 76 1/26/2026
0.1.0-prerelease0209 74 1/12/2026
0.1.0-prerelease0208 73 1/11/2026
0.1.0-prerelease0207 78 1/11/2026
0.1.0-prerelease0206 78 1/11/2026
0.1.0-prerelease0205 78 1/10/2026
0.1.0-prerelease0204 84 1/9/2026
0.1.0-prerelease0203 82 1/9/2026
0.1.0-prerelease0202 73 1/9/2026
0.1.0-prerelease0201 79 1/8/2026
0.1.0-prerelease0200 78 1/8/2026
0.1.0-prerelease0199 77 1/7/2026
0.1.0-prerelease0198 76 1/6/2026
0.1.0-prerelease0197 74 1/6/2026
0.1.0-prerelease0196 75 1/6/2026
0.1.0-prerelease0195 75 1/5/2026
0.1.0-prerelease0194 84 1/4/2026
0.1.0-prerelease0193 244 12/17/2025
Loading failed