URI:
                               Gopher games
                         by Christopher Williams
                                2025-09-15
       
       
       Last updated 2025-09-17
       
   DIR Up
   DIR Home
       
       As of September 2025, I’m designing a server-side system
       to implement multi-player turn-based games over Gopher.
       Hopefully I’ll have it more developed soon.
       
       I’ll provide some information about the design here. I’m
       still working through a lot of the details, so they’re not
       set in stone.
       
       ------------------------------------------------------------
                           High-level overview
       ------------------------------------------------------------
       
       This system will provide a common programming interface to
       game engines which will allow game logic to be separated
       from the user interface.
       
       Users can set up games, modify game settings, and play games
       through various generated pages (i.e., Gopher menus).
       
       Ongoing games will be stored in some sort of database on the
       server. A game record will contain its ID, admin user name,
       player list, and complete game state.
       
       ------------------------------------------------------------
                            The user interface
       ------------------------------------------------------------
       
       The user interface will consist of 3 different types of
       pages:
       
        * Games list
       
        * Game admin
       
        * Game player
       
       The games list is where a user can set up a new game.
       
       Once a user sets up a new game, they will have access to the
       admin page for that game instance. On this page the user can
       set various game options (e.g., Draw One or Draw Three for
       a Klondike solitaire game), add/remove/replace players, and
       start the game.
       
       Once a game starts, users can access their player page. On
       this page the user can view the current state of the game
       (e.g., see the cards on the table and in their hand, see the
       game board, or whatever), view game details, and make moves.
       Game details include any information that is too verbose to
       display on the player page. A player may make a move only on
       their turn.
       
       
       # Identifying users
       
       Users will be identified using tripcodes. A user will
       be asked for their secret at one or more places in the
       interface. (This system uses tripcodes to avoid the need for
       user signups or storing user information in the server.)
       
       ------------------------------------------------------------
                             The game engine
       ------------------------------------------------------------
       
       A game engine provides the logic of a game. With any action
       it will be provided with the complete state of a game, the
       action (as a verb-noun tuple), and the player number. It
       will return the (possibly updated) complete state of the
       game, the text to display to the user, and the set of legal
       actions the user can make (which can change depending on
       whether it’s the player’s turn or not).
       
       ------------------------------------------------------------
                             The game manager
       ------------------------------------------------------------
       
       The game manager maintains a list of available games;
       generates the games list, game admin, and game player pages;
       and passes information between the user and the game engine.
       
       It also validates user moves to ensure that a move is not
       accidentally repeated (e.g., by a user refreshing their game
       player page in the Gopher client after making a move). This
       is done by using a per-player move token. The move token
       is refreshed at certain points in the game and is included
       in each action shown in a game player page. If a selector
       includes an old or bad move token, the game engine knows not
       to perform the move but will return the same game state.
       
       ------------------------------------------------------------
                        The game engine interface
       ------------------------------------------------------------
       
       Input:
       
        * Game state (data blob)
       
        * Player number (e.g., 1)
       
        * Action (e.g., "move d2d3")
       
        * Validity of move (true/false)
       
       Output:
       
        * New game state (data blob)
       
        * Display text (will be shown to the user)
       
        * List of actions (each action consists of a verb, noun,
          and display text)
       
        * Moved (true/false)
       
       As mentioned in <<The game manager>>, the game manager
       validates user moves through move tokens. The "validity of
       move" input tells the game engine whether the move token is
       valid. If the move token is valid and the user makes a move,
       the game engine returns a true value for the "moved" output.
       This tells the game manager to refresh the move token and
       invalidate any previous move tokens. If the move is not
       valid, the game engine should not make a move but only
       display the current game state.
       
       View-only actions can generally be performed without a valid
       move token; these include viewing the current game state or
       viewing game details. The game engine should not need to
       check the move validity for these actions.
       
       ------------------------------------------------------------
          How information is passed around in the user interface
       ------------------------------------------------------------
       
       Anyone familiar with Gopher knows it doesn’t use cookies or
       anything like that to remember session information. So all
       necessary information will be passed around in selectors.
       
       On each Gopher menu, the game manager will generate
       selectors with all of the provided information (game
       ID, user secret, etc.) and information relevant to the
       specific selector (e.g., action). Since I’m designing
       this with CGI in mind, most or all of this information
       can be provided in a query string in the selector, e.g.,
       `/game/play?secret=hunter2&game=ABC123&move=roll`.
       Some game moves can be done only through user text
       input, such as in a game of Zork. These types of
       moves will use a search (type 7) selector like
       `/game/play?secret=hunter2&game=ABC123&move=%3F`; the
       percent-encoded question mark (`%3F`) will instruct the game
       manager to find the move in the search string rather than in
       the query string (special characters in query strings like
       question marks are percent-encoded per CGI).
       
       (I’m also considering other variations, where if
       the last field in the query string doesn’t have
       an equal sign, its value will automatically be
       taken from the search string. So if a user enters
       `GO DENNIS`, the query string will be transformed
       from `/game/play?secret=hunter2&game=ABC123&move`
       (in the selector) to
       `/game/play?secret=hunter2&game=ABC123&move=GO%20DENNIS` (as
       seen by the CGI in the `QUERY_STRING` variable). These are
       minor details I’m working out.)
       
       ------------------------------------------------------------
                            Go implementation
       ------------------------------------------------------------
       
       Here’s a rough draft of the game engine interface:
       
       - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
       type GameEngine interface {
           Process(state State, action Action, player int, validMove bool) (newState State, display Display, actions []Action, moved bool)
       }
       
       type Action struct {
           verb string
           noun string
           display string
       }
       
       type Display string
       
       type State interface {}
       - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
       
SEARCH