adventurelib

repository·master·Indexed 41 days ago

https://github.com/lordmauve/adventurelib

A lightweight Python library for beginners to create text-based adventure games. It provides a command-handling system using the @when decorator for pattern matching, a Bag class for item management, and an Item class for game objects. It includes features like hierarchical Command Contexts to restrict command availability, a custom prompt system, and a say() function for formatted prose output.

Tokens
5.2K
Snippets
25
Records
31
Agent score
51%

What's inside adventurelib

  1. Overview of adventurelib

    master
    adventurelib is a library designed to provide basic functionality for writing text-based adventure games. It focuses on ease of use, specifically targeting beginners. It provides the command-handling infrastructure, while higher-level game concepts like rooms, items, and characters are left for the developer to implement as they learn Python.
  2. Use hierarchical Command Contexts

    master

    Contexts can be nested using dot notation (e.g., parent.child).

    Hierarchy Rules:

    • When the current context is wonderland.flying, all commands registered to wonderland, wonderland.flying, and those with no context are available.
    • The most deeply nested context takes priority. You can use this to override command behavior or parameters in specific sub-contexts.
    # Available in 'wonderland' and 'wonderland.flying'
    @when('north', dir='north')
    
    # Overrides 'north' behavior specifically in 'confused' context
    @when('north', dir='south', context='confused')
    
    # Overrides 'north' behavior specifically in 'confused.really' sub-context
    @when('north', context='confused.really')
    def confused_north():
        say('The cauliflowers are in bloom this year.')
  3. Understand the adventurelib design philosophy

    master

    Unlike many text-based adventure engines that provide pre-built systems for rooms, items, and NPCs, adventurelib provides minimal built-in support for these structures. This is a deliberate design choice intended to force developers to model game state and business logic themselves.

    When using adventurelib, you are responsible for implementing:

    • Naming/Identity: Distinguishing between an object and the name used to refer to it.
    • References: Managing how objects hold references to other objects (traversal and manipulation).
    • Sets: Managing collections of items (bags) using set operations like membership, intersection, union, and difference.
    • Grammar: Handling parts of speech, pluralization, and sentence construction for user output.
  4. Define command responses with @when

    master

    The core mechanism of adventurelib is defining functions that execute in response to specific user commands. You use the @when decorator to map a command pattern to a Python function. The decorator supports pattern matching where placeholders (like THING) are passed as arguments to the decorated function.

    @when('take THING')
    def take(thing):
        print(f'You take the {thing}.')
        inventory.append(thing)
  5. Language limitations and non-English usage

    master

    While the adventurelib API is in English, you can write games in other languages. However, be aware of the following technical limitations regarding non-English text:

    • Word-based matching: The @when() decorator matches on the basis of words (splitting on spaces). This may not function correctly for ideographic or logographic languages.
    • Case sensitivity: Commands like @when('take ITEM') rely on uppercase/lowercase distinctions, which may not exist in all languages.
    • Built-in directions: The rooms system has built-in identifiers north, south, east, and west. While you can add your own directions, functions like room.exits() will return these English identifiers and must be translated before being displayed to the user.
    • RTL (Right-to-Left) support: The library does not currently support RTL languages. The say() function may behave unexpectedly, and @when pattern matching uses a left-to-right greedy approach.
  6. Handle greedy matching with multi-word names

    master

    Adventurelib uses a greedy algorithm for capturing values. An uppercase placeholder will 'eat' as many words as possible until it hits the next static word in the command pattern.

    To prevent unexpected behavior when capturing multiple objects, it is best practice to include static 'separator' words like to, with, or on in your command patterns. This helps the parser correctly split phrases.

    # Good: 'to' acts as a delimiter
    @when('give ITEM to RECIPIENT')
    
    # Risky: 'ITEM' might eat 'RECIPIENT' if no delimiter exists
    @when('give ITEM RECIPIENT')
  7. How Bags work for item management

    master

    A Bag is a collection of items that allows you to look up objects by the names players type. It is a set subclass, meaning it supports iteration and adding items. You can use Bag to represent player inventories, items in a room, or even groups of characters.

    Key Methods

    • bag.find(name): Returns the item matching the name without removing it. Returns None if no match is found.
    • bag.take(name): Returns the item matching the name and removes it from the bag. Returns None if no match is found.
    • bag.add(item): Adds an item to the bag if it isn't already present.
    • bag.get_random(): Returns a random item without removing it.
    • bag.take_random(): Removes and returns a random item.
    • name in bag: Checks if a name exists in the bag.
    inventory = Bag()
    
    @when('inventory')
    def show_inventory():
        print('You have:')
        for item in inventory:
            print(f'* {item}')
  8. Define directions and bi-directional exits

    master

    The Room object supports compass directions (north, south, east, west) by default. When you assign a room to one of these attributes on another room, adventurelib automatically creates a bi-directional relationship. For example, if space.north = spaceship, then spaceship.south will automatically point back to space.

    space.north = spaceship
    
    # This is automatically true:
    # spaceship.south is space
  9. Start an adventurelib project

    master

    To begin a new game, import all functions from adventurelib and call start() at the very end of your script. This initializes the game loop and allows the player to interact with the terminal.

    All game logic and command definitions must be placed between the import statement and the start() call.

    from adventurelib import *
    
    # Your game logic goes here
    
    start()
  10. Move between rooms using direction handlers

    master

    To implement movement, you can use the @when decorator with the direction keyword argument. This allows a single function to handle multiple directions by receiving the direction name as a parameter. Use current_room.exit(direction) to find the destination.

    @when('north', direction='north')
    @when('south', direction='south')
    @when('east', direction='east')
    @when('west', direction='west')
    @when('n', direction='north')
    @when('s', direction='south')
    @when('e', direction='east')
    @when('w', direction='west')
    def go(direction):
        global current_room
        room = current_room.exit(direction)
        if room:
            current_room = room
            print(f'You go {direction}.')
            # Assuming a look() function exists to show room description
            print(current_room)