Goofspiel

Summary

Goofspiel (also known as GOPS) is a simultaneous bidding card game. Each player is dealt one suit for their hand, keeping the Diamonds suit separate and shuffled. Each round, a Diamond card is turned face-up, followed by each player simultaneously privately selecting a card from their hand. Once all have chosen, the selected cards are turned face-up, and the player who played the highest rank is awarded the Diamond card. After 13 rounds, the player with the highest award cards total wins the game.

Rules of Play

These rules are summarized from https://www.pagat.com/misc/gops.html.

Variants Used

When players tie in their bids, the prize card is carried over to the next round. A tie in the last round means those cards are not awarded.

The simultaneous bidding mechanic in Goofspiel is mostly unique in traditinoal card games, but can be found in commercial games such as 6-nimmt and Turn the Tide.

Information Flow

Card Movement Graph

The diagram above visualizes information flow in Goofspiel 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).

Branching Factor

Branching Factor Graph

The figure above illustrates the branching factor (y-axis) for each decision point (x-axis) of Goofspiel, summarized over 100 random games. We define a decision point as a specific moment at which a player must choose from a set of possible actions. Following this definition, a player can be part of multiple distinct decision points during one of their turns, resulting in successive actions.

Decision Spread

Decision Spread Graph

The figure above illustrates the normalized spread (y-axis) for each decision point (x-axis) of Goofspiel, summarized over 100 games with all MCTS players. At each decision point, a player evaluates the potential moves in terms of their potential final score. The spread is the difference between the best estimated move and the worst estimated move. This value is then divided by the highest spread found during the game to calculate the normalized spread.

Lead History

Lead History Graph

The figure above illustrates the normalized average lead history (y-axis) for each decision point (x-axis) of Goofspiel, summarized over 100 games with all MCTS players. At each decision point, a player evaluates the potential moves in terms of their potential final score. For the best estimated move, they record the estimated score for all players, assigning them normalized rank estimates, where 1 is first place, and 0 is last place. Across 100 games, these histories are grouped according to final game rank, and then averaged.

RECYCLE Code

The rules for Goofspiel are coded in RECYCLE, a card game description language, to encourage standardized implementations across different systems.

You can also Download the code.

;; GOPS or Goofspiel
;; https://www.pagat.com/misc/gops.html

(game
 (setup  
  ;; Set up the players, 2 players each on their own team
  (create players 2)
  
  ;; Create the deck source
  (create deck ONE (game iloc ONE) 
   (deck (RANK (A, TWO, THREE, FOUR, FIVE, SIX, 
                SEVEN, EIGHT, NINE, TEN, J, Q, K))
         (COLOR (BLACK (SUIT (CLUBS))))))
  (create deck DEFAULT (game iloc STOCK) 
   (deck (RANK (A, TWO, THREE, FOUR, FIVE, SIX, 
                SEVEN, EIGHT, NINE, TEN, J, Q, K))
         (COLOR (RED (SUIT (DIAMONDS))))))
  (create deck TWO (game iloc TWO) (deck 
         (RANK (A, TWO, THREE, FOUR, FIVE, SIX, 
                SEVEN, EIGHT, NINE, TEN, J, Q, K))
         (COLOR (BLACK (SUIT (SPADES)))))))
 (do ( 
      
  ;; Create the deck values
  (set (game points PRECEDENCE)
   (((RANK : A)     1) ((RANK : K)    13) ((RANK : Q)    12) 
    ((RANK : J)    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)))
      
  (shuffle (game iloc STOCK))
  (repeat all
   (move (top (game iloc ONE)) 
         (top ((current player) iloc HAND))))
   (repeat all
    (move (top (game iloc TWO)) 
          (top ((next player) iloc HAND))))))
 
 ;; Stages of the game
 (stage player
  (end (all player 'P (== (size ('P iloc HAND)) 0)))
  (do (
   (move (top (game iloc STOCK))
         (top (game vloc AWARD)))))
        
  ;; players play a hidden card
  (stage player
   (end (all player 'P (== (size ('P iloc HIDDENTRICK)) 1)))               
               
   (choice (
    (do (
     (any ((current player) iloc HAND) 'C
      (move 'C (top ((current player) iloc HIDDENTRICK)))))))))
        
  (do (
   ;; Move the card to visible
   (all player 'P 
    (move (top ('P iloc HIDDENTRICK))
          (top ('P vloc TRICK))))
             
   ;; Determine who won
   ((!= (cardatt RANK (top ((current player) vloc TRICK)))
        (cardatt RANK (top ((next player) vloc TRICK))))
    (repeat all 
     (move (top (game vloc AWARD))
           (top ((owner (max (union (all player 'P ('P vloc TRICK))) 
                             using (game points PRECEDENCE))) vloc WON)))))
             
   ;; Discard cards
   (all player 'P 
    (move (top ('P vloc TRICK))
          (top (game vloc DISCARD)))))))
 
 (scoring max (sum ((current player) vloc WON) using (game points PRECEDENCE))))