Image source: By Mark Goadrich, Public Domain
In Pitch, a partnership trick-taking game, players are dealt 6 cards from a shuffled French deck. Players bid on the number of points they think their team can win. The player who bids the highest plays first and sets trump with their first card played. 6 tricks are played, with the winner of each trick leading the next trick. Points are awarded for the high, low, and jack of trump, along with a “game” point for the highest sum of cards collected. The team with the highest score wins.
These rules are summarized from https://www.pagat.com/allfours/pitch.html.
Pitch is an All Fours point trick-taking game. Other games in this genre are All Fours and Pedro.
The diagram above visualizes information flow in Pitch 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 Pitch are coded in RECYCLE, a card game description language, to encourage standardized implementations across different systems.
You can also Download the code.
;; Pitch
;; https://www.pagat.com/allfours/pitch.html
(game
(setup
;; Set up the players, 4 players, in teams of 2
(create players 4)
(create teams (1, 3) (2, 4))
;; Create the deck source
(create deck (game iloc STOCK)
(deck (RANK (ACE, TWO, THREE, FOUR, FIVE, SIX, SEVEN,
EIGHT, NINE, TEN, JACK, QUEEN, KING))
(COLOR (RED (SUIT (HEARTS, DIAMONDS)))
(BLACK (SUIT (CLUBS, SPADES)))))))
;; Get ready to play
(do (
(shuffle (game iloc STOCK))
(all player 'P
(repeat 6 (move (top (game iloc STOCK))
(top ('P iloc HAND)))))
(set (game str LEAD) NONE)
(set (game str TRUMP) NONE)
(set (game points GAME)
(((RANK : ACE) 4) ((RANK : KING) 3) ((RANK : QUEEN) 2)
((RANK : JACK) 1) ((RANK : TEN) 10)))))
;; bidding time!
(stage player
(end (all player 'P (== (game sto BIDS) 4)))
(choice (
;; not the last, you can pass, or you are last and someone already bid
((or (!= (game sto BIDS) 3)
(any player 'P (== ('P str BID) MAX)))
(inc (game sto BIDS)))
;; bid between 2 and 5, must be greater than previous
(any (range 2..5) 'B
((or (all player 'P (> 'B ('P sto BID)))
(and (== (game sto BIDS) 3) ;; the last player can steal earlier high bid
(all player 'P (> (+ 'B 1) ('P sto BID)))))
(do (
(all player 'P
((== ('P str BID) MAX)
(set ('P str BID) NONE)))
(set ((current player) str BID) MAX)
(set ((current player) sto BID) 'B)
(set ((team (current player)) sto BID) 'B)
(inc (game sto BIDS)))))))))
;; the highest bidder goes first
(do (
(all player 'P
((== ('P str BID) MAX)
(cycle current 'P)))))
;; players play a round until their cards are gone
(stage player
(end (all player 'P (== (size ('P iloc HAND)) 0)))
;; players play a hand once
(stage player
(end (all player 'P (> (size ('P vloc TRICK)) 0)))
(choice (
;; if first player, play any card, remember it in the lead spot
((== (game str LEAD) NONE)
(any ((current player) iloc HAND) 'C
(do (
(move 'C (top ((current player) vloc TRICK)))
(set (game str LEAD) (cardatt SUIT (top ((current player) vloc TRICK))))
;; if first player, then you also establish trump with your first card
((== (game str TRUMP) NONE)
(set (game str TRUMP)
(cardatt SUIT (top ((current player) vloc TRICK)))))))))
;; if following player and can follow SUIT
;; play any card that follows SUIT or TRUMP
((and (!= (game str LEAD) NONE)
(> (size (filter ((current player) iloc HAND) 'L
(== (cardatt SUIT 'L) (game str LEAD)))) 0))
(any (filter ((current player) iloc HAND) 'L
(or (== (cardatt SUIT 'L) (game str LEAD))
(== (cardatt SUIT 'L) (game str TRUMP)))) 'C
(move 'C (top ((current player) vloc TRICK)))))
;; if following player and cannot follow SUIT
;; play any card
((and (!= (game str LEAD) NONE)
(== (size (filter ((current player) iloc HAND) 'L
(== (cardatt SUIT 'L) (game str LEAD)))) 0))
(any ((current player) iloc HAND) 'C
(move 'C (top ((current player) vloc TRICK))))))))
;; after players play hand, wrap up trick
(do (
;; solidfy card recedence
(set (game points PRECEDENCE)
(((SUIT : (game str TRUMP)) 200) ((SUIT : (game str LEAD)) 100)
((RANK : ACE) 14) ((RANK : KING) 13) ((RANK : QUEEN) 12)
((RANK : JACK) 11) ((RANK : TEN) 10) ((RANK : NINE) 9)
((RANK : EIGHT) 8) ((RANK : SEVEN) 7) ((RANK : SIX) 6)
((RANK : FIVE) 5) ((RANK : FOUR) 4) ((RANK : THREE) 3)
((RANK : TWO) 2)))
;; determine who won the hand, set them first next time
(set (game str LEAD) NONE)
(cycle next (owner (max (union (all player 'P ('P vloc TRICK)))
using (game points PRECEDENCE))))
;; count the number of tricks won per team
(inc ((team (next player)) sto SMUDGE))
;; discard all the played cards
(all player 'P (move (top ('P vloc TRICK))
(top ((next player) vloc TRICKSWON)))))))
;; Start points for score
(do (
(all player 'P
(do (
;; calculate GAME point sum
(inc ((team 'P) sto GAMESCORE)
(sum ('P vloc TRICKSWON) using (game points GAME)))
;; add in HIGH, LOW, JACK from TRUMP
(let (filter (union (all player 'MP ('MP vloc TRICKSWON))) 'UC
(== (cardatt SUIT 'UC) (game str TRUMP))) 'ONLYTRUMP
(inc ((team 'P) sto TEMPSCORE)
(size (filter ('P vloc TRICKSWON) 'C
(and (== (cardatt SUIT 'C)
(game str TRUMP))
(or (== (cardatt RANK 'C) ;; HIGH
(cardatt RANK (max 'ONLYTRUMP
using (game points PRECEDENCE))))
(== (cardatt RANK 'C) ;; LOW
(cardatt RANK (min 'ONLYTRUMP
using (game points PRECEDENCE))))
(== (cardatt RANK 'C) JACK))))))))))))
;; Calculate team scores
(stage team
(end (all player 'P (== (size ('P vloc TRICKSWON)) 0)))
(do (
((> ((current team) sto GAMESCORE) ((next team) sto GAMESCORE))
(inc ((current team) sto TEMPSCORE)))
;; nonbidding team, get any points scored
((all (current team) 'TP (!= ('TP str BID) MAX))
(inc ((current team) sto SCORE) ((current team) sto TEMPSCORE)))
;; determine if bid was made, otherwise set back
((any (current team) 'TP (== ('TP str BID) MAX))
(do (
((and (<= ((current team) sto BID) 4)
(>= ((current team) sto TEMPSCORE) ((current team) sto BID)))
(inc ((current team) sto SCORE) ((current team) sto TEMPSCORE)))
((and (<= ((current team) sto BID) 4)
(< ((current team) sto TEMPSCORE) ((current team) sto BID)))
(dec ((current team) sto SCORE) ((current team) sto BID)))
;; calculate smudge
((and (== ((current team) sto BID) 5)
(== ((current team) sto SMUDGE) 6)
(== ((current team) sto TEMPSCORE) 4))
(inc ((current team) sto SCORE) 5))
((and (== ((current team) sto BID) 5)
(or (!= ((current team) sto SMUDGE) 6)
(!= ((current team) sto TEMPSCORE) 4)))
(dec ((current team) sto SCORE) 5)))))
;; discard cards
(all (current team) 'TP
(repeat all
(move (top ('TP vloc TRICKSWON))
(top (game vloc DISCARD))))))))
(scoring max ((team (current player)) sto SCORE)))