sigildocs

Chapter 11: Game World

Let's build the world for our text adventure.

The World Module

Create adventure/world.sgl:

(define-library (adventure world)
  (import (sigil struct))
  (export
   ;; Struct constructors and accessors
   room room? room-id room-name room-description room-exits room-items
   item item? item-id item-name item-description item-takeable
   game-state game-state?
   game-state-current-room
   game-state-inventory
   game-state-rooms
   game-state-items
   game-state-won

   ;; World creation
   create-world

   ;; State queries
   lookup-room
   lookup-item
   get-room-items
   room-has-exit?
   get-exit-room)

  (begin

    ;;; ========== Structs ==========

    (define-struct room
      (id)
      (name)
      (description)
      (exits default: '())
      (items default: '()))

    (define-struct item
      (id)
      (name)
      (description)
      (takeable default: #t))

    (define-struct game-state
      (current-room)
      (inventory default: '())
      (rooms)
      (items)
      (won default: #f))


    ;;; ========== World Data ==========

    (define kitchen
      (room id: 'kitchen
            name: "The Kitchen"
            description: "A cozy kitchen with copper pots hanging from the ceiling.
The morning light streams through a window over the sink.
A door leads east to the hallway."
            exits: '((east . hallway))
            items: '(knife apple)))

    (define hallway
      (room id: 'hallway
            name: "The Hallway"
            description: "A long hallway with a worn carpet runner.
Paintings of stern ancestors line the walls.
Doors lead west to the kitchen, east to the study,
and south to the garden. The front door is to the north,
but it's locked tight."
            exits: '((west . kitchen)
                     (east . study)
                     (south . garden))))

    (define study
      (room id: 'study
            name: "The Study"
            description: "A dusty study filled with books and papers.
A large oak desk dominates the room.
A door leads west to the hallway."
            exits: '((west . hallway))
            items: '(note)))

    (define garden
      (room id: 'garden
            name: "The Garden"
            description: "A beautiful garden with overgrown roses.
A stone fountain sits in the center, long dry.
Something glints beneath the dead leaves.
A path leads north back to the hallway."
            exits: '((north . hallway))
            items: '(key)))


    ;;; ========== Items ==========

    (define items-list
      (list
        (item id: 'knife
              name: "a kitchen knife"
              description: "A sharp kitchen knife. Handle with care.")
        (item id: 'apple
              name: "a red apple"
              description: "A crisp red apple. It looks delicious.")
        (item id: 'note
              name: "a crumpled note"
              description: "A handwritten note that reads:
'The key to freedom lies where water once flowed.'")
        (item id: 'key
              name: "a golden key"
              description: "A small golden key. It might unlock something important.")))


    ;;; ========== World Creation ==========

    (define (create-world)
      (game-state current-room: 'kitchen
                  inventory: '()
                  rooms: (list (cons 'kitchen kitchen)
                               (cons 'hallway hallway)
                               (cons 'study study)
                               (cons 'garden garden))
                  items: (map (lambda (i) (cons (item-id i) i))
                              items-list)))


    ;;; ========== Query Functions ==========

    (define (lookup-room state room-id)
      (let ((entry (assq room-id (game-state-rooms state))))
        (if entry (cdr entry) #f)))

    (define (lookup-item state item-id)
      (let ((entry (assq item-id (game-state-items state))))
        (if entry (cdr entry) #f)))

    (define (get-room-items state room-id)
      (let ((rm (lookup-room state room-id)))
        (if rm (room-items rm) '())))

    (define (room-has-exit? state room-id direction)
      (let ((rm (lookup-room state room-id)))
        (if rm
            (assq direction (room-exits rm))
            #f)))

    (define (get-exit-room state room-id direction)
      (let ((exit (room-has-exit? state room-id direction)))
        (if exit (cdr exit) #f)))))

Understanding the Structs

Rooms

Each room has:

  • id — Symbol for internal reference
  • name — What the player sees as the title
  • description — The full room description
  • exits — Association list mapping directions to room ids
  • items — List of item ids present in the room

Items

Each item has:

  • id — Symbol for internal reference
  • name — How it appears in room descriptions ("a golden key")
  • description — What the player sees when examining it
  • takeable — Can the player pick it up?

Game State

The game-state holds:

  • current-room — Where the player is
  • inventory — Items the player carries
  • rooms — All rooms in the world
  • items — All items in the world
  • won — Whether the player has won

Immutable State Updates

We update state by creating new structs. Pass the old struct as the first argument to copy it, then override specific fields:

;; Move to a new room
(game-state old-state current-room: 'garden)

;; Add item to inventory
(game-state old-state
            inventory: (cons 'key (game-state-inventory old-state)))

The old state remains unchanged.

Testing the World

Create a simple test file test-world.sgl:

(import (adventure world))

(define state (create-world))

;; Test room lookup
(define rm (lookup-room state 'kitchen))
(display "Kitchen: ")
(display (room-name rm))
(newline)

;; Test exits
(display "Kitchen exits: ")
(display (room-exits rm))
(newline)

;; Test items
(display "Items in kitchen: ")
(display (room-items rm))
(newline)

;; Test item lookup
(define k (lookup-item state 'key))
(display "Key description: ")
(display (item-description k))
(newline)

Run it (from the directory containing adventure/):

sigil eval -L . -f test-world.sgl

Room Connections Diagram

                    [Front Door]
                         |
                       LOCKED
                         |
[Kitchen] ---east--- [Hallway] ---east--- [Study]
                         |
                       south
                         |
                     [Garden]
                    (has key)

The player starts in the Kitchen. The key is in the Garden. Once they have the key, they can unlock the front door in the Hallway and win!

Win Condition

Notice that game-state includes a won field (defaulting to #f). We'll set this to #t when the player uses the key at the front door.

Practice Exercises

  1. Add another room (perhaps an "Attic") with a new item
  2. Create an item that can't be taken (like a heavy statue)
  3. Add more detail to room descriptions

What's Next

The world is ready! Now let's build the command parser and game logic.

Next: Game Commands →