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:
Corwin Brust 2026-07-01 14:06:02 -05:00
parent 556485cb6b
commit 69a4de7538
9 changed files with 541 additions and 19 deletions

View file

@ -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
View 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.
![img](doc/images/klondike.png)
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.
![img](doc/images/hearts.png)
# 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.

View file

@ -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
View 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

View file

@ -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

Binary file not shown.

After

Width:  |  Height:  |  Size: 89 KiB

BIN
doc/images/klondike.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

3
doc/version.texi Normal file
View file

@ -0,0 +1,3 @@
@set VERSION 1.0.90
@set UPDATED 1 July 2026
@set YEAR 2026

37
hooks/pre-commit Normal file
View 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