Node Pool and Room Distribution System - UQcsse3200/2026-studio-3 GitHub Wiki
Node Pool and Room Distribution System
Overview
The Node Pool and Room Distribution System creates the nodes used by a generated map and assigns an encounter type to each normal node.
The system is centred around the NodePoolGenerator class, which uses a MapGenerationConfig to create a configurable number of MapNode objects. The generated nodes are returned as a map keyed by node ID so they can be passed directly into MapGraph.
This system generates nodes and room types only. Graph connections, map rendering, player movement, and encounter implementation are handled by other systems.
Room Types
Each generated MapNode has a RoomType describing the encounter represented by that node:
COMBAT- a combat encounter.EVENT- a non-combat or chance encounter.SHOP- a shop encounter.ELITE- a more challenging combat encounter.START- the first node in the generated pool.FINAL- the final node in the generated pool.
Only COMBAT, EVENT, and SHOP are assigned using configurable weights. The FINAL node is created separately so every generated pool contains exactly one final node.
Room Type Constraints
assignRoomType(MapNode node, RoomType room)
Room type constraints can be defined with this function. Every node is passed through this when being added so that certain generation behaviors can be defined. For example, SHOP types not generating at layers below 3 is simply defined with:
case SHOP:
if (node.getHeight() > 2) {
node.setRoomType(room);
}
break;
Room Distribution Configuration
Room generation is configured using MapGenerationConfig.
The configuration contains:
normalNodeCount- the number of normal nodes to generate.combatWeight- the relative weight for combat rooms.eventWeight- the relative weight for event rooms.shopWeight- the relative weight for shop rooms.eliteWeight- the relative weight for elite rooms.seed- an optional seed used for repeatable random generation.
Weights are relative and do not need to add up to 100. For example, weights of 6, 2, 1, and 1 produce the same proportions as 60, 20, 10 and 10.
Weighted Room Distribution
Normal room counts are calculated proportionally from the configured weights.
For each room type, the generator:
- Calculates its proportional share of the normal node count.
- Assigns the whole-number portion of that share.
- Records the remainder left by integer division.
- Assigns any remaining nodes to the room types with the largest remainders.
For example, seven normal nodes with weights of 60, 30, and 10 produce:
- 4
COMBATnodes; - 2
EVENTnodes; - 1
SHOPnode.
This largest-remainder approach keeps small node pools close to the configured proportions without relying on statistical sampling.
Seeded Randomness
After the room counts are calculated, the room types are shuffled before nodes are created.
When a seed is supplied, the same configuration and seed produce the same room assignment for every node ID. This is useful for testing, debugging, and reproducing generated maps.
When no seed is supplied, a new random sequence is used for each generation.
Node Pool Generation
The node pool is generated using:
NodePoolGenerator.generate(MapGenerationConfig config)
The method returns an immutable Map<Integer, MapNode> where each key matches the ID of its associated node.
Normal nodes use one-based IDs from 1 to normalNodeCount - 1. The final node uses normalNodeCount as its ID and the start node uses 0 as its ID.
For example:
MapGenerationConfig config =
new MapGenerationConfig(10, 60, 20, 20, 10, 12345L);
Map<Integer, MapNode> nodes = NodePoolGenerator.generate(config);
This configuration generates ten weighted normal nodes and one additional FINAL and START node. In standard game behavior, this takes place in MapGenerationController.
Map Graph Integration
The generated node pool can be passed directly to MapGraph:
Map<Integer, MapNode> nodes = NodePoolGenerator.generate(config);
MapGraph graph = new MapGraph(nodes);
MapGraph copies the supplied nodes into its own mutable HashMap. This allows the graph system to add connections and manage progression without modifying the immutable map returned by the generator.
The generator does not create graph connections. Newly generated nodes have empty connection lists and begin in the LOCKED state.
Configuration Validation
MapGenerationConfig rejects invalid configurations before generation begins.
The following configurations are invalid:
- a normal node count below one;
- a negative combat, event, or shop weight;
- all room weights being zero.
Weight totals and weighted node calculations use long arithmetic to prevent integer overflow.
Relevant Classes
NodePoolGenerator- creates the ID-keyed node pool and assigns room types.MapGenerationConfig- stores and validates node count, room weights, and the optional seed.MapGenerationController- mediates interactions between map related classes for a closed system.MapNode- represents an individual generated node.RoomType- defines the supported encounter types.MapGraph- receives the generated node map and manages graph connections and progression.
Testing
Unit tests for the Node Pool and Room Distribution System are located in:
Current tests cover node counts, unique ID mapping, final-node creation, weighted distribution, largest-remainder allocation, seeded reproducibility, zero-weight room types, large-weight arithmetic, immutable output, empty graph connections, missing seeds, null configuration, and invalid configuration values.