Skip to content

Board Generation

When you generate a bingo board, all available non-disabled objectives from the JSON are loaded into a single “pool” of possible goals. Each objective appears in the pool exactly once, regardless of how many times it can be used on the board. An objective with a limit of 3 doesn’t get added to the pool 3 times - it’s still just one goal in the pool.

Individual limits control how many times a specific objective can appear on the board

Most objectives have a limit of 1, so they can only appear once per board. Some objectives have higher limits (like 2 or 3), allowing them to appear multiple times

Most importantly, every objective in the pool has an equal chance of being selected, regardless of its individual limit

After an objective is picked, its limit decreases by 1. When it hits 0, that objective is completely removed from the pool.

For a goal to have an individual limit higher than 1, it must make use of ranges.

Objectives have can variable numbers within the goal (like “Catch X Pokemon” where X could be 5, 10, or 15)

The objective is chosen first, and then a random number is chosen from the available list of ranges

If the same objective appears multiple times (due to an individual limit higher than 1) then a different range is chosen each time

  • Scope: Apply to the entire board
  • Purpose: Control the overall composition and balance of the entire board
  • Example: Only allowing 25% of the board be combat objectives
  • Scope: Apply to each individual lines (each row, column and diagonal separately)
  • Purpose: Prevent clustering of goals with similar progression and ensure variety within each line
  • Example: Only allowing 1 goal in a line to be a combat objective

At its core, although they have some overlap, they solve different problems.

Board categories solve macro level balance

  • Board shouldn’t be dominated by one type of objective, i.e. combat
  • We want equal representation of categories, i.e. exploration, combat, collection, cooking etc

Line categories solve micro-level fairness

  • Getting a bingo line shouldn’t require only one skill type
  • Getting a bingo line shouldn’t consist of goals that have significant synergy and overlap, where completing one almost completes the others

You could successfully limit a board with up to 25% combat goals but without the line categories you could end up with 5 combat goals in a row.

You could successfully limit combat goals to max 2 in a row, but without board categories you could have up to 40% of the board being combat related.

You could have the same “category” apply to both the line and board limits, but they’d often need to have different values.

With the example above, the combat board category would be 25% and the combat line category would be 40%.

How objectives get placed on the board:

The category limits are created first. The games JSON contains the percentage limits for each category (clamped between 0 and 100%). This is translated into a corresponding number for the given board size, rounding up.

I.e. A board category of 25% for a 5x5 board is a max of 7 (rounded up from 6.25). A line category of 33% for a 5x5 board is a max of 2 per line (rounded up from 1.6)

A category of 0% sets the limit to 1.

Some objectives have predetermined spots. These get placed first, ignoring restrictions

Remaining spots are filled randomly from the available pool of objectives

A random position is selected on the board. The pool of remaining objectives is then temporarily filtered, so that only goals that meet the following can be picked for the spot:

  • Duplicate Prevention: Duplicate objectives (i.e. goal with individual limit of higher than 1) can’t appear twice in the same line, so are removed
  • Line Limits: Any objectives that would violate any row, column and (if applicable) diagonal line limits are removed
  • Board Limits: Any objectives that are part of a board category that has no more quota left, are removed

From the remaining objectives, a random one is selected

For the selected goal, every board category it has gets decremented by 1. The individual limit then gets decremented by 1. If the individual limit becomes 0, the goal is removed from the pool.

Step 3 then repeats, until the board is filled up

If, at any point, the limits are too restrictive (i.e. the filtered objective pool becomes empty) and no valid objectives remain, the system will:

  • Issue a warning about which constraint was too restrictive
  • Temporarily ignore some constraints to complete the board, selecting any goal from the pool to fill the spot