- C# 100%
| CardKit | ||
| Solitaire | ||
| .gitignore | ||
| CardGames.slnx | ||
| README.md | ||
CardKit
A small .NET library for building things with playing cards. CardKit handles the
cards themselves — a deck you can fill, shuffle, deal from, peek into and move
around — and everything else is built on top of it.
Right now the repo ships two things:
- CardKit — the actual library. A
Cardtype and aDeckthat behaves like a real stack of cards. - Solitaire — a console Klondike game that doubles as a demo of what CardKit can do.
The long-term idea is for the Solitaire project to grow into a more general CLI "card game engine", but that's just a direction, not a promise. For now: it's a deck of cards, with Solitaire as the demo.
Requirements
- .NET 10 SDK
- A terminal with 24-bit (truecolor) ANSI support — the rendering uses
\e[38;2;r;g;bescape sequences, so an 8/16-color-only terminal will look wrong.
Running the demos
Everything runs through the Solitaire project, which takes a mode argument:
dotnet run --project Solitaire game # play Klondike Solitaire
dotnet run --project Solitaire full # render a full 52-card deck, reshuffle on keypress (default)
dotnet run --project Solitaire stack # render solitaire-style stacks of up to 7
dotnet run --project Solitaire debug # tiny sanity check
If you omit the argument it defaults to full.
Playing Solitaire
Standard Klondike: seven tableau columns, a stock + waste, and four foundations. The goal is to move every card up onto the foundations (which empties the tableau — that's the win condition the game checks for).
Controls:
| Key | Action |
|---|---|
1–7 |
Select a tableau column. Valid moves auto-resolve. |
Space |
Cycle a card from the stock into the waste. |
Enter |
Move the top waste card onto the tableau or a foundation. |
F |
Move a card from a foundation back down to the tableau. |
Q |
Quit. |
E |
Forfeit and reveal all cards. |
The column selection is a single-key auto-resolve: pressing a column number tries to place its cards (a foundation move first, otherwise onto another column), rather than asking you to pick a source and a destination.
Using CardKit in your own project
CardKit isn't published to NuGet, so reference the project directly. Add it to your
.csproj:
<ItemGroup>
<ProjectReference Include="path/to/CardKit/CardKit.csproj" />
</ItemGroup>
or from the CLI:
dotnet add reference path/to/CardKit/CardKit.csproj
Then the basics:
using CardKit;
var deck = new Deck(52); // capacity 52, face-down by default
deck.Fill(); // populate with a sorted deck (up to the capacity)
deck.Shuffle(); // in-place Fisher–Yates
Card drawn = deck.Top(); // remove and return the top card
Card look = deck.Peek(); // look at the top without removing it
deck.Insert(drawn); // put a card back on top (adopts the deck's facing)
Note: the console-drawing helper (
PaintUtil) lives in the Solitaire project, not in CardKit — it's part of the demo/rendering layer. CardKit itself is render-agnostic. If you want colored output you can liftPaintUtilas a starting point and adapt it.
Deck Of Cards — API reference
Card(Suit suit, Rank rank, bool faceUp)
| Member | Description |
|---|---|
Suit, Rank |
The card's suit and rank (Rank.Ace == 1 … Rank.King). |
FaceUp |
Whether the card is face up. Settable. |
IsRed |
True for Hearts and Diamonds. |
Glyph |
Suit symbol (♣ ♦ ❤ ♠). |
RankName |
Short rank label (A, 2…T, J, Q, K). |
ToString() |
e.g. "♠ K". |
Deck : IEnumerable<Card>
Constructors:
Deck(int cardMax = 52, bool faceUp = false)— empty deck with a capacity and default facing.Deck(List<Card> cards, bool faceUp = false)— wrap an existing list.
| Member | Description |
|---|---|
Count / IsEmpty |
Number of cards / whether the deck is empty. |
Fill() |
Add sorted cards until the deck reaches CardMaximum. |
Shuffle() |
In-place Fisher–Yates shuffle. |
Insert(Card) |
Add a card on top; the card adopts the deck's FaceUp. |
Peek(int index = 0) |
Look at a card from the top (0 = topmost). Throws DeckIsEmptyException if empty. |
TryPeek() |
Like Peek() but returns null on an empty deck instead of throwing. |
Top() |
Remove and return the top card. Throws DeckIsEmptyException if empty. |
TakeTop(int count) |
Remove the top count cards, returned bottom-to-top (ready to Insert() in sequence). |
Cycle() |
Move the top card to the bottom and return the new top — handy for looping displays. |
MoveToDeck(Deck other) |
Move every card into another deck (used e.g. to recycle the waste back into the stock). |
CorrectFacing() / (bool) |
Flip all cards to the deck's facing, or to an explicit direction. |
DeckIsEmptyException is thrown by the operations noted above when they can't act on
an empty deck.
AI usage
AI was used during development to help design the deck/card system, to write some
utility helpers (notably the ANSI truecolor drawing in PaintUtil), and to draft this
README. The rest of the code was written by me.