Scenario Workflow - lil-lab/cb2 GitHub Wiki

CB2 Scenario Workflow & Documentation

Introduction

CB2 supports scenarios, which allow you to recreate a moment in time from a game. You can also craft custom scenarios by editing a scenario file. We also provide a map editor tool (documented below) to create custom maps. If you have a scenario file already, you can skip to the section “Loading a scenario”. If you just want to try an example scenario, you can get a scenario file from the “Example Scenarios” section.

Example Scenarios

We provide some example scenarios to demonstrate the CB2 environment. You can find them here. Each JSON file is a scenario you can upload and try following the instructions in this doc. These were made using the map editor, which is documented below.

Loading a Scenario

  • Go to the scenario lobby (just 1 browser window this time): cb2.ai/play?lobby_name=scenario-lobby and hit “Join Game”.
  • You should be immediately taken to an empty, foggy map as the follower. Hit escape. You should see “Upload Scenario State” as an option. Sometimes it doesn’t appear. If that happens, refresh the page and try again.

alt_text

  • Select the file you saved in the Creating a Scenario File. It should now load! If you didn’t send an instruction as leader previously, or you didn’t end your turn, the follower (you) will be unable to move. That can be fixed though….
  • The Scenario file format makes use of HECS hexagon coordinates. If this is confusing, try to think of it as two interlaced square grids. To figure out your current coordinates, as well as the coordinates in front and behind you, hit “P” to see the coordinate overlay (pictured below in the bottom right).

alt_text

Creating a Scenario

In order to create a scenario, we start a random CB2 game and use the in-game UI to save a scenario state file.

  • Open two browser windows in the open lobby: cb2.ai/play?lobby_name=open
  • Hit Join Game on each. Try not to wait too long in between, or someone else might join and get connected with one of your clients.
  • In the leader window, send an instruction, then hit End Turn.

alt_text

  • Hit Escape, then Save Scenario State.

alt_text

Modifying Scenarios (Scenario File Format)

The scenario file format is a JSON file, with its schema defined by the Scenario dataclass.

Adding more moves

Ctrl + F “turn_state” and change “moves_remaining” to desired number of moves.

Adding Instructions

Ctrl + F “objectives” and add additional objectives. Recommend choosing a scenario which already has an objective in it (send an instruction when first creating your scenario!) so you have a template to copy.

“uuid” has no requirements, except that it must be a unique string among all the other instruction UUIDs. “completed” and “cancelled” should be false.

Changing who’s turn it is

Change “turn” in “turn_state”. Values:

1 - means follower

2 - means leader

Editing the map

This is best done using the map editor. You can install the repo at

https://github.com/lil-lab/cb2

And then follow the python setup instructions on the main page. There's some documentation in the README on CB2 scenarios and the map editor.

From the repository, with the virtual env enabled, run the map editor with:

python3 -m cb2game.server.map_tools.map_editor

(No further command line parameters, it’ll pop-up a GUI asking you for a scenario file, and on close it pops up another GUI to save the modified scenario).

The map editor is very new, so read this part carefully…

alt_text

There is no undo button, so save frequently and create copies of your files. The red button clears everything and the green button saves. The other buttons are (right pane) cells to place or (bottom pane) cards to place. Hitting tab/escape or switching away also closes the window. But it’ll again pop up a UI asking where to save progress. If you don’t save, you lose your work.

Removing Cards

Select 0 in the card editor pane to delete cards -- then click on cards you'd like to remove.

Defining Custom Goal Cards.

New: In the card creation tool panel, there's a row with options "N" and "G". This lets you select between normal and goal cards. If any cards on a map are goal cards, then the scenario's normal set-making rules will be replaced with a new set of rules: To simply select all goal cards (and no non-goal cards). This will cause the score to increase, and then the scenario will wait for any monitoring script to detect the score and load a new scenario.

Deleting a goal card is similar to deleting a normal card.

alt_text

Resizing the Map

To shrink the board, change “rows” and “cols” vals in the “map” section of the JSON file and then re-open the scenario in the map editor (this isn't supported in the GUI).

Scenario Scripting

The API is defined in src/cb2game/pyclient/game_endpoint.py here. In particular, take note of classes GameEndpoint and Action

If you are writing a script to control scenarios, I recommend you check out the scenario_monitor demo utility here. Your code will likely be similar, in particular, the code to actually connect to a CB2 server:

def main(host, scenario_id="", render=False, lobby="scenario-lobby", scenario_file=""):
    logging.basicConfig(level=logging.INFO)
    logger.info(f"Connecting to {host} (render={render}) (scenario_id={scenario_id})")
    client = RemoteClient(host, render, lobby_name=lobby)
    connected, reason = client.Connect()
    assert connected, f"Unable to connect: {reason}"

    game, reason = client.AttachToScenario(
        scenario_id=scenario_id,
        timeout=timedelta(minutes=5),
    )

    # If scenario_file is specified, read the scenario from the file.
    scenario_data = ""
    if scenario_file:
        with open(scenario_file, "r") as f:
            scenario_data = f.read()

    assert game is not None, f"Unable to join game: {reason}"
    # See scenario_monitor.py for implementation of ScenarioMonitor
    monitor = ScenarioMonitor(
        game, pause_per_turn=(1 / REFRESH_RATE_HZ), scenario_data=scenario_data
    )
    monitor.run()
    monitor.join()

There’s also a special load scenario Action to upload a scenario JSON file. Here’s how it’s used in scenario_monitor.py:

            if self.scenario_data:
                logger.info(f"Loading scenario...")
                self.game.step(Action.LoadScenario(self.scenario_data))
⚠️ **GitHub.com Fallback** ⚠️