Image source: By — Belbury, CC-SA 4.0
In Crazy Eights, players attempt to empty their hands of cards. Each player is dealt 5 cards from the deck to start, and one card is turned up from the deck to begin the discard pile. On a player’s turn, they can either play a card that matches either the suit or rank of the top card on the the discard pile, or draw the top card from the face-down deck. A card with a suit of 8 can be played at any time. The first player to empty their hand is the winner, and all other players score points according to the rank of the cards they have remaining.
These rules are summarized from https://www.pagat.com/eights/crazy8s.html.
In this version of Crazy Eights, players are required to play a matching card or an eight if they are able. A player can only draw a card if there is no option for them to play.
Crazy Eights is a matching shedding game. Other games similar to Crazy Eights include Bartok and Page One, along with the commercial game Uno.
The diagram above visualizes information flow in Crazy Eights using a single random rollout in CardStock. Visibility is attached to card locations, so all cards in a location share the same visibility; information is revealed or concealed as cards move between locations and ownership changes.
Public locations are shown in green, hidden locations in yellow, private locations in blue, and memory locations in light gray. Locations containing cards with distinct backs are indicated with bold borders. Rectangles denote ownership (players or table), and directed edges show card movement between locations and resulting visibility changes. Taken information is shown with red dotted edges (public to private/hidden), and shared information with blue dashed edges (private cards transferred to another player).
The rules for Crazy Eights are coded in RECYCLE, a card game description language, to encourage standardized implementations across different systems.
You can also Download the code.
;; Crazy Eights
;; https://www.pagat.com/eights/crazy8s.html
(game
(declare (HEARTS, DIAMONDS, CLUBS, SPADES) 'SUITS)
(setup
;; Set up the players, 3 players each on their own team
(create players 3)
;; Create the deck source
(create deck (game iloc STOCK)
(deck (RANK (A, TWO, THREE, FOUR, FIVE, SIX,
SEVEN, EIGHT, NINE, TEN, J, Q, K))
(COLOR (RED (SUIT (HEARTS, DIAMONDS)))
(BLACK (SUIT (SPADES, CLUBS)))))))
(do (
(set (game points SCORE)
(((RANK : A) 1) ((RANK : K) 10) ((RANK : Q) 10)
((RANK : J) 10) ((RANK : TEN) 10) ((RANK : NINE) 9)
((RANK : EIGHT) 50) ((RANK : SEVEN) 7) ((RANK : SIX) 6)
((RANK : FIVE) 5) ((RANK : FOUR) 4) ((RANK : THREE) 3)
((RANK : TWO) 2)))
;; Shuffle and give each player 5 cards
(shuffle (game iloc STOCK))
(all player 'P
(repeat 5 (move (top (game iloc STOCK))
(top ('P iloc HAND)))))
;; Start the discard pile
(move (top (game iloc STOCK))
(top (game vloc DISCARD)))
;; If an eight on top, just pick HEARTS to be the start suit.
((== (cardatt RANK (top (game vloc DISCARD))) EIGHT)
(set (game str EIGHTSUIT) HEARTS))))
;; Game over when any player has 0 cards in their hand
(stage player
(end (any player 'P (== (size ('P iloc HAND)) 0)))
;; player makes a choice
(choice (
;; Play a card that matches suit or rank on top of discard
((!= (cardatt RANK (top (game vloc DISCARD))) EIGHT)
(any (filter ((current player) iloc HAND) 'NH
(and (!= (cardatt RANK 'NH) EIGHT)
(or (== (cardatt SUIT 'NH)
(cardatt SUIT (top (game vloc DISCARD))))
(== (cardatt RANK 'NH)
(cardatt RANK (top (game vloc DISCARD))))))) 'C
(move 'C (top (game vloc DISCARD)))))
;; play a card that matches the chosen suit for the EIGHT on discard
((== (cardatt RANK (top (game vloc DISCARD))) EIGHT)
(any (filter ((current player) iloc HAND) 'NH
(and (!= (cardatt RANK 'NH) EIGHT)
(== (cardatt SUIT 'NH)
(game str EIGHTSUIT)))) 'C
(move 'C (top (game vloc DISCARD)))))
;; Can play eight any time
(any (filter ((current player) iloc HAND) 'NH
(== (cardatt RANK 'NH) EIGHT)) 'C
(do (
(move 'C (top (game vloc DISCARD)))
(any 'SUITS 'S
(set (game str EIGHTSUIT) 'S)))))
;; Draw from the Stock when no other options available
((== (size (filter ((current player) iloc HAND) 'NH
(or (== (cardatt RANK 'NH) EIGHT)
(and (== (cardatt RANK (top (game vloc DISCARD))) EIGHT)
(== (cardatt SUIT 'NH) (game str EIGHTSUIT)))
(and (!= (cardatt RANK (top (game vloc DISCARD))) EIGHT)
(or (== (cardatt SUIT 'NH)
(cardatt SUIT (top (game vloc DISCARD))))
(== (cardatt RANK 'NH)
(cardatt RANK (top (game vloc DISCARD))))))))) 0)
(do (
;; if STOCK is empty, resupply from discard
((== (size (game iloc STOCK)) 0)
(do (
(move (top (game vloc DISCARD)) (top (game vloc TEMP)))
(repeat all
(move (top (game vloc DISCARD)) (top (game iloc STOCK))))
(move (top (game vloc TEMP)) (top (game vloc DISCARD)))
(shuffle (game iloc STOCK)))))
;; draw a card from the stock
(move (top (game iloc STOCK))
(top ((current player) iloc HAND)))))))))
;; Player with the smallest hand score wins
(scoring min (sum ((current player) iloc HAND) using (game points SCORE))))