doc: generate README.md from README.org (Emacs batch ox-md)
Add build.el + pre-commit hook so README.org stays the source and README.md is regenerated for GitHub/MELPA. Refresh README (screenshots, Crapette, use-package, new customs). Makefile: readme/hooks/info-emacs targets; ship README.md.
This commit is contained in:
parent
556485cb6b
commit
69a4de7538
9 changed files with 541 additions and 19 deletions
56
Makefile
56
Makefile
|
|
@ -12,13 +12,16 @@ SRCTAR = $(PKG)-$(VERSION)-src.tar.gz
|
||||||
DIST = dist
|
DIST = dist
|
||||||
BATCH = $(EMACS) -Q --batch -L .
|
BATCH = $(EMACS) -Q --batch -L .
|
||||||
MANUAL = doc/card-games.texi
|
MANUAL = doc/card-games.texi
|
||||||
|
VERTEXI = doc/version.texi
|
||||||
INFO = doc/card-games.info
|
INFO = doc/card-games.info
|
||||||
|
IMAGES = doc/images/klondike.png doc/images/hearts.png
|
||||||
MAKEINFO ?= makeinfo
|
MAKEINFO ?= makeinfo
|
||||||
TEXI2PDF ?= texi2pdf
|
TEXI2PDF ?= texi2pdf
|
||||||
EXTRA = README.org $(PKGDESC) $(MANUAL)
|
README = README.md
|
||||||
|
EXTRA = README.org $(README) $(PKGDESC) $(MANUAL) $(VERTEXI) $(IMAGES)
|
||||||
|
|
||||||
.PHONY: all compile test clean distclean checkdoc lint package tarball elpa release help \
|
.PHONY: all compile test clean distclean checkdoc lint package tarball elpa release help \
|
||||||
info html pdf docclean
|
info info-emacs html pdf docclean version readme hooks
|
||||||
|
|
||||||
help:
|
help:
|
||||||
@echo "card-games $(VERSION) -- make targets:"
|
@echo "card-games $(VERSION) -- make targets:"
|
||||||
|
|
@ -26,7 +29,11 @@ help:
|
||||||
@echo " test run the ERT test suite"
|
@echo " test run the ERT test suite"
|
||||||
@echo " checkdoc run checkdoc on all sources"
|
@echo " checkdoc run checkdoc on all sources"
|
||||||
@echo " lint run package-lint (if installed)"
|
@echo " lint run package-lint (if installed)"
|
||||||
@echo " info build the Info manual ($(INFO))"
|
@echo " version regenerate $(VERTEXI) from VERSION"
|
||||||
|
@echo " readme export README.org -> README.md (Emacs batch)"
|
||||||
|
@echo " hooks install the git pre-commit hook"
|
||||||
|
@echo " info build the Info manual ($(INFO)) with makeinfo"
|
||||||
|
@echo " info-emacs build the Info manual with Emacs alone (fallback)"
|
||||||
@echo " html build the one-file HTML manual"
|
@echo " html build the one-file HTML manual"
|
||||||
@echo " pdf build the PDF manual (needs a TeX installation)"
|
@echo " pdf build the PDF manual (needs a TeX installation)"
|
||||||
@echo " package build the installable package tarball ($(TAR))"
|
@echo " package build the installable package tarball ($(TAR))"
|
||||||
|
|
@ -74,8 +81,8 @@ elpa: tarball
|
||||||
# Source snapshot for a GitHub release. Archive an explicit file list
|
# Source snapshot for a GitHub release. Archive an explicit file list
|
||||||
# (not ".") so the growing output tarball and editor lock files are never
|
# (not ".") so the growing output tarball and editor lock files are never
|
||||||
# read mid-write -- which is what caused "tar: .: file changed as we read it".
|
# read mid-write -- which is what caused "tar: .: file changed as we read it".
|
||||||
SRCFILES = $(EL) $(EXTRA) Makefile .gitignore test
|
SRCFILES = $(EL) $(EXTRA) build.el hooks Makefile .gitignore test
|
||||||
release: distclean test tarball
|
release: distclean version readme test tarball
|
||||||
rm -f $(SRCTAR)
|
rm -f $(SRCTAR)
|
||||||
tar --transform 's,^,$(TARDIR)/,' \
|
tar --transform 's,^,$(TARDIR)/,' \
|
||||||
--exclude='*.elc' --exclude='*.tar' --exclude='*.tar.gz' \
|
--exclude='*.elc' --exclude='*.tar' --exclude='*.tar.gz' \
|
||||||
|
|
@ -84,15 +91,46 @@ release: distclean test tarball
|
||||||
@echo "Built $(SRCTAR) and $(TAR) for release $(VERSION)"
|
@echo "Built $(SRCTAR) and $(TAR) for release $(VERSION)"
|
||||||
|
|
||||||
# Documentation. The Texinfo source lives in doc/; the Info manual is
|
# Documentation. The Texinfo source lives in doc/; the Info manual is
|
||||||
# built from it with makeinfo.
|
# built from it with makeinfo. doc/version.texi carries the version and
|
||||||
|
# is committed; `make version' regenerates it from VERSION (run at release).
|
||||||
|
version:
|
||||||
|
@printf '@set VERSION %s\n@set UPDATED %s\n@set YEAR %s\n' \
|
||||||
|
"$(VERSION)" "$$(date '+%-d %B %Y')" "$$(date +%Y)" > $(VERTEXI)
|
||||||
|
@echo "Wrote $(VERTEXI) (VERSION $(VERSION))"
|
||||||
|
|
||||||
|
# README: Org is the source; GitHub and MELPA render Markdown better than
|
||||||
|
# Org, so we export README.org -> README.md with Emacs batch (ox-md). The
|
||||||
|
# git pre-commit hook (make hooks) keeps README.md in step automatically.
|
||||||
|
readme: $(README)
|
||||||
|
$(README): README.org build.el
|
||||||
|
$(BATCH) -l build.el
|
||||||
|
|
||||||
|
# Install the pre-commit hook into this checkout's .git/hooks.
|
||||||
|
hooks:
|
||||||
|
@if [ -d .git ]; then \
|
||||||
|
cp hooks/pre-commit .git/hooks/pre-commit && \
|
||||||
|
chmod +x .git/hooks/pre-commit && \
|
||||||
|
echo "Installed .git/hooks/pre-commit"; \
|
||||||
|
else \
|
||||||
|
echo "No .git directory here; skipping hook install."; \
|
||||||
|
fi
|
||||||
|
|
||||||
info: $(INFO)
|
info: $(INFO)
|
||||||
$(INFO): $(MANUAL)
|
$(INFO): $(MANUAL) $(VERTEXI)
|
||||||
$(MAKEINFO) -o $@ $(MANUAL)
|
$(MAKEINFO) -o $@ $(MANUAL)
|
||||||
|
|
||||||
html: $(MANUAL)
|
# Fallback: build the Info manual with Emacs alone (no makeinfo needed).
|
||||||
|
# Handy on Windows/MSYS2 where Emacs is present but texinfo may not be.
|
||||||
|
# The native formatter is lower fidelity than makeinfo, so `make info'
|
||||||
|
# stays the default; this is only for a makeinfo-less environment.
|
||||||
|
info-emacs: $(MANUAL) $(VERTEXI)
|
||||||
|
cd doc && $(EMACS) -Q --batch --eval "(require 'texinfmt)" \
|
||||||
|
-f batch-texinfo-format card-games.texi
|
||||||
|
|
||||||
|
html: $(MANUAL) $(VERTEXI)
|
||||||
$(MAKEINFO) --html --no-split -o doc/card-games.html $(MANUAL)
|
$(MAKEINFO) --html --no-split -o doc/card-games.html $(MANUAL)
|
||||||
|
|
||||||
pdf: $(MANUAL)
|
pdf: $(MANUAL) $(VERTEXI)
|
||||||
cd doc && $(TEXI2PDF) -q card-games.texi
|
cd doc && $(TEXI2PDF) -q card-games.texi
|
||||||
|
|
||||||
docclean:
|
docclean:
|
||||||
|
|
|
||||||
306
README.md
Normal file
306
README.md
Normal file
|
|
@ -0,0 +1,306 @@
|
||||||
|
Card games for Emacs: about thirty of them, from Klondike and FreeCell
|
||||||
|
to Hearts, 500, Gin, Cribbage, and two-player Russian Bank against the
|
||||||
|
computer. Every game plays with the keyboard everywhere and with the
|
||||||
|
mouse on a graphical display.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
On a graphical display the cards are drawn as SVG; in a terminal they
|
||||||
|
fall back to UNICODE glyphs (customize `card-game-symbols`). You can
|
||||||
|
switch how every game is drawn from the menu – `text` (UNICODE),
|
||||||
|
`svg` (drawn cards), or `full` (a full-window SVG table) – and dial the
|
||||||
|
computer opponents between `easy`, `normal`, and `hard`.
|
||||||
|
|
||||||
|
A full Info manual ships with the package: after installing, `C-h i` and
|
||||||
|
choose **Card Games**, or `M-x info RET (card-games) RET`.
|
||||||
|
|
||||||
|
|
||||||
|
# Games
|
||||||
|
|
||||||
|
To open the game menu type `M-x card-game`, or start a game directly
|
||||||
|
with its command. From the menu you can also switch the card treatment
|
||||||
|
(text / SVG / full-window) and the AI difficulty.
|
||||||
|
|
||||||
|
|
||||||
|
## Trick-taking
|
||||||
|
|
||||||
|
- `cg-bid` – 500 (Bid). Win the auction, name the trump suit, then take
|
||||||
|
tricks with your partner to reach 500 points before the opposing pair.
|
||||||
|
Also playable live over the network (`M-x cg-bid-host` / `cg-bid-join`).
|
||||||
|
- `cg-hearts` – Hearts. Avoid taking hearts and the Queen of Spades, or
|
||||||
|
take them all to "shoot the moon"; lowest score loses.
|
||||||
|
- `cg-spades` – Spades. Partnership bidding to 500; spades are always
|
||||||
|
trump. Make your side's combined bid, mind the bags, dare a nil.
|
||||||
|
- `cg-whist` – Whist. Trump is the turned card, there is no bidding;
|
||||||
|
score one point for each trick past the book of six.
|
||||||
|
- `cg-ohhell` – Oh Hell. The hand shrinks each round; bid the exact
|
||||||
|
number of tricks you will take, no more and no fewer.
|
||||||
|
|
||||||
|
|
||||||
|
## Solitaire
|
||||||
|
|
||||||
|
- `cg-montana` – Montana (also called Gaps). Each row is anchored by a
|
||||||
|
Two and built upward in one suit, 2 through King; slide cards into the
|
||||||
|
gaps until all four rows are sorted.
|
||||||
|
- `cg-gaps` – an alias for `cg-montana`.
|
||||||
|
- `cg-hells-half-acre` – the build-down variant: each row is anchored by
|
||||||
|
a King and built downward, King through 2.
|
||||||
|
- `cg-klondike` – Klondike, the classic "Solitaire": build the four
|
||||||
|
foundations up by suit from the Ace.
|
||||||
|
- `cg-freecell` – FreeCell: every card in view, four free cells, a game
|
||||||
|
of nearly pure skill.
|
||||||
|
- `cg-spider` – Spider (two decks): build down regardless of suit, but
|
||||||
|
only same-suit runs move; clear eight King-to-Ace runs.
|
||||||
|
- `cg-yukon` – Yukon: Klondike's layout dealt mostly face up, with any
|
||||||
|
buried group movable and no stock.
|
||||||
|
- `cg-canfield` – Canfield: a 13-card reserve and a foundation base rank
|
||||||
|
set by the deal; foundations wrap King to Ace.
|
||||||
|
- `cg-forty-thieves` – Forty Thieves: two decks, ten columns, eight
|
||||||
|
foundations, build down by suit, and no second pass through the stock.
|
||||||
|
- `cg-scorpion` – Scorpion: build down by suit and free any buried group
|
||||||
|
to assemble four King-to-Ace runs.
|
||||||
|
- `cg-golf` – Golf: clear the layout by playing exposed cards one rank
|
||||||
|
above or below the waste top.
|
||||||
|
- `cg-tripeaks` – TriPeaks: the same, on three overlapping peaks, with
|
||||||
|
Ace-King wrapping for long chains.
|
||||||
|
- `cg-pyramid` – Pyramid: remove pairs of exposed cards whose ranks sum
|
||||||
|
to thirteen; Kings go alone.
|
||||||
|
|
||||||
|
|
||||||
|
## Shedding and climbing
|
||||||
|
|
||||||
|
- `cg-eights` – Crazy Eights. Match the suit or rank of the discard;
|
||||||
|
eights are wild and let you name the next suit.
|
||||||
|
- `cg-president` – President (Scum). Climb: play one to four of a rank,
|
||||||
|
beat it or pass; first out rules, last out scrubs, and the roles trade
|
||||||
|
cards on the next deal.
|
||||||
|
|
||||||
|
|
||||||
|
## Rummy
|
||||||
|
|
||||||
|
- `cg-gin` – Gin Rummy. A two-handed duel: draw or take the discard,
|
||||||
|
build sets and runs, and knock once your deadwood is ten or less, or go
|
||||||
|
gin with none; your opponent then lays off and may undercut you. First
|
||||||
|
to 100 wins.
|
||||||
|
- `cg-rummy-basic` – Rummy. Meld sets and runs onto the table and lay
|
||||||
|
cards off onto them; empty your hand to go out and score the cards left
|
||||||
|
in the other hands.
|
||||||
|
- `cg-rum500` – Rummy 500. As above, but you score the cards you lay
|
||||||
|
down and lose the cards left in your hand; first past 500 wins. Take a
|
||||||
|
buried discard card with `T`: you take it and every card above it, and
|
||||||
|
meld the chosen card at once.
|
||||||
|
- `cg-handfoot` – Hand & Foot. A partnership Canasta cousin: play a hand
|
||||||
|
and then a foot, build books of a rank with Twos and Jokers wild, and go
|
||||||
|
out once your side has completed two of them. Each round opens with a
|
||||||
|
rising go-down minimum (50, 90, 120, 150); red threes are bonus cards;
|
||||||
|
and you can pick up the discard pile (`p`) by melding its top card with
|
||||||
|
two matching naturals.
|
||||||
|
|
||||||
|
|
||||||
|
## Matching
|
||||||
|
|
||||||
|
- `cg-go-fish` – Go Fish. Ask another player for a rank you hold;
|
||||||
|
collect all four to lay down a book, and make the most books.
|
||||||
|
- `cg-old-maid` – Old Maid. One Queen is set aside; discard pairs and
|
||||||
|
draw blind from your neighbour, and do not be left with the odd Queen.
|
||||||
|
|
||||||
|
|
||||||
|
## Pegging
|
||||||
|
|
||||||
|
- `cg-cribbage` – Cribbage. Lay two cards to the crib, cut a starter,
|
||||||
|
peg toward 31, then count fifteens, pairs, runs, flushes, and his nobs.
|
||||||
|
Two-handed to 121.
|
||||||
|
|
||||||
|
|
||||||
|
## Capturing
|
||||||
|
|
||||||
|
- `cg-scopa` – Scopa. A 40-card deck; capture table cards by value and
|
||||||
|
sweep the board for a scopa. Score cards, coins, the sette bello, and
|
||||||
|
primiera to 11.
|
||||||
|
- `cg-casino` – Casino. The full deck; capture by pairs and sums and
|
||||||
|
score cards, spades, the casinos, and aces to 21.
|
||||||
|
|
||||||
|
|
||||||
|
## More trick-taking
|
||||||
|
|
||||||
|
- `cg-euchre` – Euchre. A 24-card deck with the two bowers; order up or
|
||||||
|
call trump and take three of five tricks. Partnership to 10.
|
||||||
|
- `cg-pitch` – Auction Pitch. Bid for the pitch; your first lead sets
|
||||||
|
trump. Score High, Low, Jack, and Game; first to 7.
|
||||||
|
- `cg-briscola` – Briscola. A fixed trump turned from the deal and no
|
||||||
|
obligation to follow suit; capture the Aces and Threes. Partnership to
|
||||||
|
61 of the 120 points.
|
||||||
|
|
||||||
|
|
||||||
|
## Climbing patience
|
||||||
|
|
||||||
|
- `cg-spite` – Spite & Malice. Race the computer to empty your goal
|
||||||
|
pile onto shared centre piles that build Ace to Queen; Kings are wild.
|
||||||
|
|
||||||
|
|
||||||
|
## Bridge
|
||||||
|
|
||||||
|
- `cg-bridge` – Contract Bridge. A full auction (bids, pass, double,
|
||||||
|
redouble), play with the dummy exposed, and classic rubber scoring with
|
||||||
|
vulnerability. You are South; when you declare you play the dummy too.
|
||||||
|
The bidding AI is a small natural system, sensible but no expert.
|
||||||
|
|
||||||
|
|
||||||
|
## Two-player patience
|
||||||
|
|
||||||
|
- `cg-russian-bank` / `cg-crapette` – Russian Bank (Crapette). A race
|
||||||
|
against the computer: build the eight shared foundations up by suit,
|
||||||
|
build the shared houses down in alternating colour, and empty your
|
||||||
|
reserve to win. Load your cards onto your opponent's piles when the
|
||||||
|
rank and suit line up, mind the "stop" rule that ends your turn if you
|
||||||
|
skip a foundation play, and sequence house-to-house moves within the
|
||||||
|
free houses (`[` / `]` choose how many cards of a run to drop on an
|
||||||
|
empty house). The opponent plays all three difficulty levels.
|
||||||
|
|
||||||
|
|
||||||
|
# TODO
|
||||||
|
|
||||||
|
- [X] make the suit symbols customizable (`cg-symbols`) and obey them
|
||||||
|
- [X] a Texinfo manual
|
||||||
|
- [ ] finish `checkdoc` docstrings across the per-game files
|
||||||
|
(the shared engine files are clean; `make compile` is warning-free)
|
||||||
|
- [ ] renderer "skins": let games subclass the display components (text,
|
||||||
|
SVG, full-window SVG)
|
||||||
|
- [X] a manual card-size control for the full-window SVG UI
|
||||||
|
- [ ] more games
|
||||||
|
|
||||||
|
|
||||||
|
# Install
|
||||||
|
|
||||||
|
|
||||||
|
## From the package tarball
|
||||||
|
|
||||||
|
make package # builds card-games-1.0.90.tar
|
||||||
|
|
||||||
|
Then in Emacs: `M-x package-install-file RET card-games-1.0.90.tar`.
|
||||||
|
|
||||||
|
|
||||||
|
## With `use-package`
|
||||||
|
|
||||||
|
Once the package is on your `load-path` (installed from the tarball or an
|
||||||
|
ELPA archive), the whole collection loads from the single `card-games`
|
||||||
|
feature:
|
||||||
|
|
||||||
|
(use-package card-games
|
||||||
|
:commands (card-game cg-klondike cg-bid cg-hearts cg-gin cg-crapette))
|
||||||
|
|
||||||
|
Then `M-x card-game` for the menu.
|
||||||
|
|
||||||
|
|
||||||
|
## From a local ELPA archive
|
||||||
|
|
||||||
|
make elpa # builds dist/ (archive-contents + tar)
|
||||||
|
|
||||||
|
(add-to-list 'package-archives '("cg" . "/path/to/dist/"))
|
||||||
|
(package-refresh-contents)
|
||||||
|
(package-install 'card-games)
|
||||||
|
|
||||||
|
|
||||||
|
## Manually
|
||||||
|
|
||||||
|
Put the `cg-*.el` and `card-games.el` files on your `load-path` and
|
||||||
|
`(require 'card-games)`.
|
||||||
|
|
||||||
|
|
||||||
|
# Manual
|
||||||
|
|
||||||
|
A complete Info manual is included. After installing, `C-h i` and pick
|
||||||
|
**Card Games**, or `M-x info RET (card-games) RET`. To build it from a
|
||||||
|
source checkout:
|
||||||
|
|
||||||
|
make info # builds doc/card-games.info with makeinfo
|
||||||
|
|
||||||
|
The manual text is licensed CC-BY-4.0; the code is GPL-3.0-or-later.
|
||||||
|
|
||||||
|
|
||||||
|
# Playing
|
||||||
|
|
||||||
|
Every game works with the keyboard everywhere and with the mouse on a
|
||||||
|
graphical display.
|
||||||
|
|
||||||
|
- 500: `b` bid, `p` pass, arrows + `RET` to play (or click a card),
|
||||||
|
`n` next hand / new game, `?` help.
|
||||||
|
- Gaps: arrows to move (or `hjkl` when `cg-keys` is `classic`), `RET` to
|
||||||
|
fill a gap (or click it), `r` redeal, `u` undo, `n` new, `?` help.
|
||||||
|
- Klondike / FreeCell / Spider / Yukon: arrows move between piles, `RET`
|
||||||
|
picks up a movable run and drops it, `f` sends a card to a foundation,
|
||||||
|
`a` auto-plays everything it can, `u` undo, `n` new, `?` help. On the
|
||||||
|
stock pile, `RET` deals or recycles.
|
||||||
|
- Hearts / Spades: arrows choose a card, `RET` plays it (in Hearts, `RET`
|
||||||
|
marks a card to pass and `p` sends the three), `n` new match, `?` help.
|
||||||
|
- Crazy Eights: arrows choose, `RET` plays, `d` draws, `x` passes, `n`
|
||||||
|
new deal, `?` help.
|
||||||
|
|
||||||
|
On a graphical display, `v` toggles the full-window SVG table. A
|
||||||
|
**Card size** slider (and the `+` / `-` / `0` keys) resizes the cards, and
|
||||||
|
in 500 the `? Help / Rules` button explains play. Every game accepts the
|
||||||
|
mouse: click cards, board slots, buttons, and the slider.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
|
||||||
|
# Testing
|
||||||
|
|
||||||
|
This is a 1.0.90 pre-test snapshot. To try it:
|
||||||
|
|
||||||
|
1. `make compile && make test` – should be warning-free and all green.
|
||||||
|
2. `M-x card-game` opens the menu, or jump straight in, e.g.
|
||||||
|
`M-x cg-klondike`, `M-x cg-bid` (500), `M-x cg-gin`, `M-x cg-handfoot`.
|
||||||
|
3. On a graphical display, press `v` in 500 for the full-window SVG
|
||||||
|
table and play entirely with the mouse: click a bid, click five kitty
|
||||||
|
cards and the **Discard** button, click cards to play, move the **Card
|
||||||
|
size** slider, and open `? Help / Rules`.
|
||||||
|
|
||||||
|
Feedback most wanted: anything a mouse-only player who is new to Emacs
|
||||||
|
finds confusing or unreachable, rules bugs, and rendering glitches.
|
||||||
|
|
||||||
|
|
||||||
|
# Customization
|
||||||
|
|
||||||
|
`M-x customize-group RET cg-svg` and `RET card-games`:
|
||||||
|
|
||||||
|
- `cg-ai-level` – how hard the computer plays: `easy`, `normal`, or
|
||||||
|
`hard` (also on the `M-x card-game` menu, or `M-x
|
||||||
|
card-games-set-ai-level`).
|
||||||
|
- `card-games-treatment` – how the games are drawn: `text`, `svg`, or
|
||||||
|
`full` (also on the menu, or `M-x card-games-set-treatment`).
|
||||||
|
- `cg-svg-theme-colors` – derive the highlight ring and card backs
|
||||||
|
from your theme (on by default).
|
||||||
|
- `cg-svg-highlight-color` – the cursor/selection ring (gold by default).
|
||||||
|
- `cg-bid-felt-color` – the 500 table felt.
|
||||||
|
- `cg-svg-card-width`, `cg-svg-card-height`, `cg-svg-card-shadow`,
|
||||||
|
`cg-svg-font-family` – card appearance.
|
||||||
|
- `cg-svg-card-back` – the card-back design: `dots`, `rings`, `solid`,
|
||||||
|
`lattice`, `waves`, `diamond`, an Emacs-logo back (`emacs`,
|
||||||
|
`emacs-classic`, `gnu`, `splash`), or `random` (the default – picks
|
||||||
|
one for the session; `M-x cg-svg-shuffle-card-back` rolls a new one).
|
||||||
|
- `cg-svg-emacs-logo` – the emblem on the full-window table:
|
||||||
|
`modern` (default), `classic`, `gnu`, `splash`, `drawn`, or `none`.
|
||||||
|
- `cg-symbols` – the Unicode suit glyphs (and the joker) drawn on cards.
|
||||||
|
- `cg-svg-four-color` – draw a four-colour deck (clubs green, diamonds
|
||||||
|
blue-purple).
|
||||||
|
- `cg-keys` – `emacs` (default) or `classic` (adds vi-style `hjkl` and
|
||||||
|
`SPC`).
|
||||||
|
- `cg-bid-animate`, `cg-bid-ai-delay`, `cg-bid-trick-pause` – pace the
|
||||||
|
500 AI so play is watchable and completed tricks linger.
|
||||||
|
- `M-x card-games-set-theme` – apply a preset (classic, dark, contrast).
|
||||||
|
|
||||||
|
|
||||||
|
# Development
|
||||||
|
|
||||||
|
make compile # byte-compile (should be warning-free)
|
||||||
|
make test # run the ERT suite
|
||||||
|
make checkdoc # documentation lint
|
||||||
|
make release # clean + test + package + source tarball
|
||||||
|
|
||||||
|
|
||||||
|
# License
|
||||||
|
|
||||||
|
GPL-3.0-or-later. See the file headers; add a COPYING file with the
|
||||||
|
full GPLv3 text for distribution.
|
||||||
|
|
||||||
70
README.org
70
README.org
|
|
@ -1,16 +1,28 @@
|
||||||
#+TITLE: card-games -- Play card games in Emacs
|
#+TITLE: card-games -- Play card games in Emacs
|
||||||
#+AUTHOR: Corwin Brust
|
#+AUTHOR: Corwin Brust
|
||||||
|
#+OPTIONS: toc:nil
|
||||||
|
|
||||||
Card games for Emacs.
|
Card games for Emacs: about thirty of them, from Klondike and FreeCell
|
||||||
|
to Hearts, 500, Gin, Cribbage, and two-player Russian Bank against the
|
||||||
|
computer. Every game plays with the keyboard everywhere and with the
|
||||||
|
mouse on a graphical display.
|
||||||
|
|
||||||
Renders SVG by default when ~display-graphic-p~ is t and rsvg is
|
[[file:doc/images/klondike.png]]
|
||||||
available. The default (UNICODE) symbols maybe customized by
|
|
||||||
configuring ~card-game-symbols~.
|
On a graphical display the cards are drawn as SVG; in a terminal they
|
||||||
|
fall back to UNICODE glyphs (customize ~card-game-symbols~). You can
|
||||||
|
switch how every game is drawn from the menu -- ~text~ (UNICODE),
|
||||||
|
~svg~ (drawn cards), or ~full~ (a full-window SVG table) -- and dial the
|
||||||
|
computer opponents between ~easy~, ~normal~, and ~hard~.
|
||||||
|
|
||||||
|
A full Info manual ships with the package: after installing, ~C-h i~ and
|
||||||
|
choose *Card Games*, or ~M-x info RET (card-games) RET~.
|
||||||
|
|
||||||
* Games
|
* Games
|
||||||
|
|
||||||
To open the game menu type ~M-x card-game~, or start a game directly
|
To open the game menu type ~M-x card-game~, or start a game directly
|
||||||
with its command.
|
with its command. From the menu you can also switch the card treatment
|
||||||
|
(text / SVG / full-window) and the AI difficulty.
|
||||||
|
|
||||||
** Trick-taking
|
** Trick-taking
|
||||||
- ~cg-bid~ -- 500 (Bid). Win the auction, name the trump suit, then take
|
- ~cg-bid~ -- 500 (Bid). Win the auction, name the trump suit, then take
|
||||||
|
|
@ -116,9 +128,19 @@ with its command.
|
||||||
vulnerability. You are South; when you declare you play the dummy too.
|
vulnerability. You are South; when you declare you play the dummy too.
|
||||||
The bidding AI is a small natural system, sensible but no expert.
|
The bidding AI is a small natural system, sensible but no expert.
|
||||||
|
|
||||||
|
** Two-player patience
|
||||||
|
- ~cg-russian-bank~ / ~cg-crapette~ -- Russian Bank (Crapette). A race
|
||||||
|
against the computer: build the eight shared foundations up by suit,
|
||||||
|
build the shared houses down in alternating colour, and empty your
|
||||||
|
reserve to win. Load your cards onto your opponent's piles when the
|
||||||
|
rank and suit line up, mind the "stop" rule that ends your turn if you
|
||||||
|
skip a foundation play, and sequence house-to-house moves within the
|
||||||
|
free houses (~[~ / ~]~ choose how many cards of a run to drop on an
|
||||||
|
empty house). The opponent plays all three difficulty levels.
|
||||||
|
|
||||||
* TODO
|
* TODO
|
||||||
- [X] make the suit symbols customizable (~cg-symbols~) and obey them
|
- [X] make the suit symbols customizable (~cg-symbols~) and obey them
|
||||||
- [ ] a Texinfo manual
|
- [X] a Texinfo manual
|
||||||
- [ ] finish ~checkdoc~ docstrings across the per-game files
|
- [ ] finish ~checkdoc~ docstrings across the per-game files
|
||||||
(the shared engine files are clean; ~make compile~ is warning-free)
|
(the shared engine files are clean; ~make compile~ is warning-free)
|
||||||
- [ ] renderer "skins": let games subclass the display components (text,
|
- [ ] renderer "skins": let games subclass the display components (text,
|
||||||
|
|
@ -133,6 +155,16 @@ make package # builds card-games-1.0.90.tar
|
||||||
#+end_src
|
#+end_src
|
||||||
Then in Emacs: ~M-x package-install-file RET card-games-1.0.90.tar~.
|
Then in Emacs: ~M-x package-install-file RET card-games-1.0.90.tar~.
|
||||||
|
|
||||||
|
** With ~use-package~
|
||||||
|
Once the package is on your ~load-path~ (installed from the tarball or an
|
||||||
|
ELPA archive), the whole collection loads from the single ~card-games~
|
||||||
|
feature:
|
||||||
|
#+begin_src emacs-lisp
|
||||||
|
(use-package card-games
|
||||||
|
:commands (card-game cg-klondike cg-bid cg-hearts cg-gin cg-crapette))
|
||||||
|
#+end_src
|
||||||
|
Then ~M-x card-game~ for the menu.
|
||||||
|
|
||||||
** From a local ELPA archive
|
** From a local ELPA archive
|
||||||
#+begin_src
|
#+begin_src
|
||||||
make elpa # builds dist/ (archive-contents + tar)
|
make elpa # builds dist/ (archive-contents + tar)
|
||||||
|
|
@ -147,8 +179,17 @@ make elpa # builds dist/ (archive-contents + tar)
|
||||||
Put the ~cg-*.el~ and ~card-games.el~ files on your ~load-path~ and
|
Put the ~cg-*.el~ and ~card-games.el~ files on your ~load-path~ and
|
||||||
~(require 'card-games)~.
|
~(require 'card-games)~.
|
||||||
|
|
||||||
|
* Manual
|
||||||
|
A complete Info manual is included. After installing, ~C-h i~ and pick
|
||||||
|
*Card Games*, or ~M-x info RET (card-games) RET~. To build it from a
|
||||||
|
source checkout:
|
||||||
|
#+begin_src
|
||||||
|
make info # builds doc/card-games.info with makeinfo
|
||||||
|
#+end_src
|
||||||
|
The manual text is licensed CC-BY-4.0; the code is GPL-3.0-or-later.
|
||||||
|
|
||||||
* Playing
|
* Playing
|
||||||
Both games work with the keyboard everywhere and with the mouse on a
|
Every game works with the keyboard everywhere and with the mouse on a
|
||||||
graphical display.
|
graphical display.
|
||||||
|
|
||||||
- 500: ~b~ bid, ~p~ pass, arrows + ~RET~ to play (or click a card),
|
- 500: ~b~ bid, ~p~ pass, arrows + ~RET~ to play (or click a card),
|
||||||
|
|
@ -169,6 +210,8 @@ On a graphical display, ~v~ toggles the full-window SVG table. A
|
||||||
in 500 the ~? Help / Rules~ button explains play. Every game accepts the
|
in 500 the ~? Help / Rules~ button explains play. Every game accepts the
|
||||||
mouse: click cards, board slots, buttons, and the slider.
|
mouse: click cards, board slots, buttons, and the slider.
|
||||||
|
|
||||||
|
[[file:doc/images/hearts.png]]
|
||||||
|
|
||||||
* Testing
|
* Testing
|
||||||
This is a 1.0.90 pre-test snapshot. To try it:
|
This is a 1.0.90 pre-test snapshot. To try it:
|
||||||
1. ~make compile && make test~ -- should be warning-free and all green.
|
1. ~make compile && make test~ -- should be warning-free and all green.
|
||||||
|
|
@ -184,12 +227,23 @@ finds confusing or unreachable, rules bugs, and rendering glitches.
|
||||||
|
|
||||||
* Customization
|
* Customization
|
||||||
~M-x customize-group RET cg-svg~ and ~RET card-games~:
|
~M-x customize-group RET cg-svg~ and ~RET card-games~:
|
||||||
|
- ~cg-ai-level~ -- how hard the computer plays: ~easy~, ~normal~, or
|
||||||
|
~hard~ (also on the ~M-x card-game~ menu, or ~M-x
|
||||||
|
card-games-set-ai-level~).
|
||||||
|
- ~card-games-treatment~ -- how the games are drawn: ~text~, ~svg~, or
|
||||||
|
~full~ (also on the menu, or ~M-x card-games-set-treatment~).
|
||||||
- ~cg-svg-theme-colors~ -- derive the highlight ring and card backs
|
- ~cg-svg-theme-colors~ -- derive the highlight ring and card backs
|
||||||
from your theme (on by default).
|
from your theme (on by default).
|
||||||
|
- ~cg-svg-highlight-color~ -- the cursor/selection ring (gold by default).
|
||||||
- ~cg-bid-felt-color~ -- the 500 table felt.
|
- ~cg-bid-felt-color~ -- the 500 table felt.
|
||||||
- ~cg-svg-card-width~, ~cg-svg-card-height~, ~cg-svg-card-shadow~,
|
- ~cg-svg-card-width~, ~cg-svg-card-height~, ~cg-svg-card-shadow~,
|
||||||
~cg-svg-font-family~ -- card appearance.
|
~cg-svg-font-family~ -- card appearance.
|
||||||
- ~cg-svg-card-back~ -- card-back pattern: dots, rings, or solid.
|
- ~cg-svg-card-back~ -- the card-back design: ~dots~, ~rings~, ~solid~,
|
||||||
|
~lattice~, ~waves~, ~diamond~, an Emacs-logo back (~emacs~,
|
||||||
|
~emacs-classic~, ~gnu~, ~splash~), or ~random~ (the default -- picks
|
||||||
|
one for the session; ~M-x cg-svg-shuffle-card-back~ rolls a new one).
|
||||||
|
- ~cg-svg-emacs-logo~ -- the emblem on the full-window table:
|
||||||
|
~modern~ (default), ~classic~, ~gnu~, ~splash~, ~drawn~, or ~none~.
|
||||||
- ~cg-symbols~ -- the Unicode suit glyphs (and the joker) drawn on cards.
|
- ~cg-symbols~ -- the Unicode suit glyphs (and the joker) drawn on cards.
|
||||||
- ~cg-svg-four-color~ -- draw a four-colour deck (clubs green, diamonds
|
- ~cg-svg-four-color~ -- draw a four-colour deck (clubs green, diamonds
|
||||||
blue-purple).
|
blue-purple).
|
||||||
|
|
|
||||||
77
build.el
Normal file
77
build.el
Normal file
|
|
@ -0,0 +1,77 @@
|
||||||
|
;;; build.el --- Batch Org -> Markdown export for card-games -*- lexical-binding: t; -*-
|
||||||
|
|
||||||
|
;; Copyright (C) 2026 Corwin Brust
|
||||||
|
;; SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
;;; Commentary:
|
||||||
|
|
||||||
|
;; A very small Emacs-batch exporter. It renders the project's Org
|
||||||
|
;; sources to Markdown siblings (foo.org -> foo.md) using the built-in
|
||||||
|
;; `ox-md' backend, so GitHub and MELPA -- which render Markdown more
|
||||||
|
;; faithfully than Org -- can display them.
|
||||||
|
;;
|
||||||
|
;; Run it by hand, from the Makefile, or from the git pre-commit hook:
|
||||||
|
;;
|
||||||
|
;; emacs -Q --batch -l build.el
|
||||||
|
;;
|
||||||
|
;; By default it exports the files named in `build-org-files' (README.org).
|
||||||
|
;; Set the CARD_GAMES_ORG environment variable to a space-separated list
|
||||||
|
;; to override that, e.g. to export more documents. It never touches
|
||||||
|
;; known-games.org (an internal research list) unless you ask for it.
|
||||||
|
|
||||||
|
;;; Code:
|
||||||
|
|
||||||
|
(require 'org)
|
||||||
|
(require 'ox-md)
|
||||||
|
|
||||||
|
;; Keep batch mode from blocking on prompts.
|
||||||
|
(setq org-confirm-babel-evaluate nil
|
||||||
|
org-export-show-temporary-export-buffer nil
|
||||||
|
;; A stray or not-yet-committed image link must never abort the run.
|
||||||
|
org-export-with-broken-links 'mark
|
||||||
|
make-backup-files nil)
|
||||||
|
|
||||||
|
(defvar build-org-files '("README.org")
|
||||||
|
"Default list of Org files to export to Markdown.
|
||||||
|
Overridden by the CARD_GAMES_ORG environment variable when set.")
|
||||||
|
|
||||||
|
(defvar build-inhibit-run nil
|
||||||
|
"When non-nil, loading build.el defines helpers but does not export.
|
||||||
|
ERT or an interactive session can bind this to exercise the helpers.")
|
||||||
|
|
||||||
|
(defun build--targets ()
|
||||||
|
"Return the list of Org files to export.
|
||||||
|
Honours the CARD_GAMES_ORG environment variable; falls back to
|
||||||
|
`build-org-files'."
|
||||||
|
(let ((env (getenv "CARD_GAMES_ORG")))
|
||||||
|
(if (and env (not (string-empty-p (string-trim env))))
|
||||||
|
(split-string (string-trim env) "[ \t\n]+" t)
|
||||||
|
build-org-files)))
|
||||||
|
|
||||||
|
(defun build--export-one (orgfile)
|
||||||
|
"Export ORGFILE to a Markdown sibling.
|
||||||
|
Log the outcome; never signal, so one bad file cannot abort the run."
|
||||||
|
(cond
|
||||||
|
((not (file-readable-p orgfile))
|
||||||
|
(message "build: SKIP %s (not readable)" orgfile))
|
||||||
|
(t
|
||||||
|
(message "build: exporting %s -> markdown" orgfile)
|
||||||
|
(with-current-buffer (find-file-noselect orgfile)
|
||||||
|
(condition-case err
|
||||||
|
(let ((out (org-md-export-to-markdown)))
|
||||||
|
(message "build: wrote %s" out))
|
||||||
|
(error
|
||||||
|
(message "build: ERROR exporting %s: %s"
|
||||||
|
orgfile (error-message-string err))))))))
|
||||||
|
|
||||||
|
(defun build--run ()
|
||||||
|
"Export every file in `build--targets' to Markdown."
|
||||||
|
(dolist (orgfile (build--targets))
|
||||||
|
(build--export-one orgfile))
|
||||||
|
(message "build: done"))
|
||||||
|
|
||||||
|
(unless (bound-and-true-p build-inhibit-run)
|
||||||
|
(build--run))
|
||||||
|
|
||||||
|
(provide 'build)
|
||||||
|
;;; build.el ends here
|
||||||
|
|
@ -8,8 +8,7 @@
|
||||||
@syncodeindex fn cp
|
@syncodeindex fn cp
|
||||||
@c %**end of header
|
@c %**end of header
|
||||||
|
|
||||||
@set VERSION 1.0.90
|
@include version.texi
|
||||||
@set YEAR 2026
|
|
||||||
|
|
||||||
@copying
|
@copying
|
||||||
This manual is for Card Games for Emacs (version @value{VERSION}), an
|
This manual is for Card Games for Emacs (version @value{VERSION}), an
|
||||||
|
|
@ -81,6 +80,10 @@ Card Games for Emacs is a collection of more than thirty card games ---
|
||||||
solitaires, two-player games, and four-handed partnership games ---
|
solitaires, two-player games, and four-handed partnership games ---
|
||||||
played entirely inside GNU Emacs.
|
played entirely inside GNU Emacs.
|
||||||
|
|
||||||
|
@ifnotinfo
|
||||||
|
@center @image{images/klondike, , , Klondike solitaire in Emacs, png}
|
||||||
|
@end ifnotinfo
|
||||||
|
|
||||||
Every game draws itself two ways. In a terminal it uses plain UNICODE
|
Every game draws itself two ways. In a terminal it uses plain UNICODE
|
||||||
text, so it works anywhere Emacs runs, including over @command{ssh} and
|
text, so it works anywhere Emacs runs, including over @command{ssh} and
|
||||||
on a phone. On a graphical display it draws proper SVG cards, with a
|
on a phone. On a graphical display it draws proper SVG cards, with a
|
||||||
|
|
@ -599,6 +602,10 @@ the highest card (or the highest trump) wins it. You sit South; the
|
||||||
other three seats are computer players, and for the partnership games
|
other three seats are computer players, and for the partnership games
|
||||||
North is your partner.
|
North is your partner.
|
||||||
|
|
||||||
|
@ifnotinfo
|
||||||
|
@center @image{images/hearts, , , A hand of Hearts, png}
|
||||||
|
@end ifnotinfo
|
||||||
|
|
||||||
@cindex trick games, controls
|
@cindex trick games, controls
|
||||||
Most of them share these controls:
|
Most of them share these controls:
|
||||||
|
|
||||||
|
|
|
||||||
BIN
doc/images/hearts.png
Normal file
BIN
doc/images/hearts.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 89 KiB |
BIN
doc/images/klondike.png
Normal file
BIN
doc/images/klondike.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 64 KiB |
3
doc/version.texi
Normal file
3
doc/version.texi
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
@set VERSION 1.0.90
|
||||||
|
@set UPDATED 1 July 2026
|
||||||
|
@set YEAR 2026
|
||||||
37
hooks/pre-commit
Normal file
37
hooks/pre-commit
Normal file
|
|
@ -0,0 +1,37 @@
|
||||||
|
#!/usr/bin/env sh
|
||||||
|
# hooks/pre-commit -- regenerate README.md from README.org on commit.
|
||||||
|
#
|
||||||
|
# When README.org (or build.el) is part of the commit, re-run the batch
|
||||||
|
# Org -> Markdown export and stage the refreshed README.md so it travels
|
||||||
|
# in the same commit. GitHub and MELPA render Markdown better than Org.
|
||||||
|
#
|
||||||
|
# Lightweight by design: no sentinel file, no post-commit --amend. If
|
||||||
|
# nothing relevant changed, the hook exits immediately.
|
||||||
|
#
|
||||||
|
# Install: make hooks (or: ln -s ../../hooks/pre-commit .git/hooks/pre-commit)
|
||||||
|
#
|
||||||
|
# Set EMACS in the environment if the Emacs binary is not named "emacs"
|
||||||
|
# on the PATH git sees (common on Windows/MSYS2).
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
REPO_ROOT="$(git rev-parse --show-toplevel)"
|
||||||
|
cd "$REPO_ROOT"
|
||||||
|
|
||||||
|
# Only act when README.org or the exporter itself is staged.
|
||||||
|
if ! git diff --cached --name-only | grep -Eq '^(README\.org|build\.el)$'; then
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
EMACS_BIN="${EMACS:-emacs}"
|
||||||
|
if ! command -v "$EMACS_BIN" >/dev/null 2>&1; then
|
||||||
|
echo "pre-commit: WARNING: '$EMACS_BIN' not found; README.md not regenerated." >&2
|
||||||
|
echo "pre-commit: set EMACS to your Emacs binary, or run 'make readme'." >&2
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "pre-commit: regenerating README.md from README.org"
|
||||||
|
"$EMACS_BIN" -Q --batch -l build.el
|
||||||
|
|
||||||
|
git add README.md
|
||||||
|
exit 0
|
||||||
Loading…
Add table
Add a link
Reference in a new issue