Chemistry Lab 3D: OOP, Data Structures, and Algorithms

This document explains how the desktop Unity/C# game works internally. It focuses on direct examples from the codebase: how objects collaborate, which data structures hold game state, and which algorithms resolve chemistry, safety, UI, audio, and movement.

Runtime Snapshot

52 periodic elements
40 chemicals
38 curated reactions
9 dynamic rule families
7 condition profiles
8 redox rules
155 generated valid pairs
565 accepted coordinates
541 unique formulas
45 reviewed compound overrides
15 procedural audio clips

Source: BuildReports/desktop-validation-report.json.

Direct Gameplay Flow

1

Player aims and presses E

FirstPersonChemistController raycasts from the camera and finds the focused LabInteractable.

2

Interactable chooses action

A bottle calls SelectChemical; a vessel calls AddSelectedToVessel; the sink calls WashVessels.

3

Game updates state

DesktopLabGame stores selected chemicals and vessel contents in dictionaries keyed by LabStation.

4

Chemistry is evaluated

ReactionSimulator checks curated, redox, then dynamic rules. ReactionConditionEngine gates the match using temperature, concentration, pH, and catalyst.

5

Safety is applied

LabSafetySystem computes exposure, health loss, credits lost, and evacuation state for hazardous gases.

6

Player receives feedback

DesktopLabHud, DesktopLabAudio, materials, and particles show the result.

OOP in the Game

Encapsulation

ChemicalDefinition hides its fields behind private setters. Once a chemical is created, other systems read its formula, phase, hazards, color, and physical properties without mutating the catalogue.

Inheritance

LabInteractable is an abstract base class. Specific objects inherit from it and implement Prompt and Interact().

Polymorphism

The player controller only knows it has a LabInteractable. It does not need to know whether the target is a bottle, vessel, sink, analysis bench, or periodic element tile.

Composition

DesktopLabGame composes HUD, audio, diagnostics, world objects, safety state, materials, and player controller. This matches Unity's component style.

Plain C# Domain Objects

Chemistry data classes such as ReactionDefinition, VesselAddition, and ReactionOutcome are not Unity components. They can be validated in editor/build code without scene dependencies.

Sealed Classes

Runtime data models are marked sealed when inheritance is not intended. This keeps behavior easier to reason about and avoids accidental subclass contracts.

OOP Example: Interactions

LabInteractable
|-- ChemicalBottleInteractable  -> Game.SelectChemical(chemicalId)
|-- VesselInteractable          -> Game.AddSelectedToVessel(station)
|-- SinkInteractable            -> Game.WashVessels()
|-- AnalysisInteractable        -> Game.ToggleInspector(true)
`-- ElementTileInteractable     -> Game.InspectElement(atomicNumber)

The important point is that FirstPersonChemistController runs one generic interaction algorithm: raycast, focus, show prompt, call Interact(). The object itself decides what the action means.

Data Structures

Structure Where It Appears Why It Fits
List<ChemicalDefinition> DesktopChemistryDatabase Ordered catalogue traversal for shelves, validation, and UI listings.
Dictionary<string, ChemicalDefinition> ChemicalById Fast lookup when gameplay only has a chemical id such as copper-sulfate.
Dictionary<LabStation, List<VesselAddition>> DesktopLabGame.vesselAdditions Separates workbench and fume hood vessel contents while keeping each vessel's addition history.
Dictionary<LabStation, VesselVisual> DesktopLabGame.vesselVisuals Maps simulation state to the correct 3D liquid renderer and particle system.
Dictionary<string, Material> DesktopLabGame.materials Caches generated Unity materials so repeated colors and chemical surfaces do not create duplicate runtime assets.
Dictionary<string, Species> DynamicReactionEngine.SpeciesById Connects catalogue chemicals to ion/species metadata for rule-based chemistry.
Dictionary<string, ChemistryIonDefinition> CompoundGenerationMatrix Provides constant-time lookup of the 46 reusable ions loaded from JSON.
Dictionary<string, MatrixCompoundOverrideRecord> CompoundGenerationMatrix Maps one X/Y/Z coordinate to reviewed formula, phase, solubility, colour, hazard, and evidence metadata.
HashSet<string> Validation code Detects duplicate chemical ids, duplicate reaction ids, and duplicate element symbols.
IReadOnlyList<T> Public catalogues and simulator input Lets systems read catalogue data without taking ownership or changing it.
enum ChemicalPhase, ReactionEffect, HazardSeverity Represents small fixed state sets clearly and cheaply.

Algorithms

Reaction Matching

ReactionSimulator.Evaluate aggregates grams by chemical id, checks every curated reaction for both reactants, and uses the curated match when available. This preserves hand-authored observations and safety notes.

curated first dictionary aggregation

Dynamic Reaction Resolution

DynamicReactionEngine.TryResolve sorts valid ids, checks every two-chemical pair, dispatches by species kind, and builds a generated ReactionDefinition when a rule family applies.

pair search rule dispatch

Stoichiometry

The simulator converts grams to moles, divides by reaction coefficients, chooses the smaller extent as the limiting reagent, then estimates product mass from molar mass and yield fraction.

limiting reagent mass balance

Reaction Conditions and Kinetics

ReactionConditionEngine converts mass to molarity, computes net acid/base-equivalent pH, applies temperature and concentration trends, verifies catalysts, and returns a rate class, completion time, and yield multiplier. Failed hard constraints return Blocked without consuming the vessel.

pH / molarity condition gate

Redox Electron Balance

RedoxReactionEngine stores electron loss and gain for two half-reactions. Euclid's GCD algorithm produces their least common multiple, which validates the shared electron count and supports acid/concentration product branches.

GCD / LCM half-reactions

Persistent Product Mass

SynthesizedInventory serializes batches to JSON. Loading reconstructs runtime chemical definitions; reusing a batch subtracts the requested mass and removes an empty batch. Matrix-backed products register as dynamic species.

JSON persistence mass accounting

Formula Construction

CompoundGenerationMatrix combines cations and anions by charge using a greatest-common-divisor reduction. Polyatomic ions are parenthesized when count is greater than one, then reviewed overrides and exclusions are applied.

GCD ion charge

Balancing Search

Exchange, gas-release, displacement, and metal-acid reactions use bounded coefficient searches. The search space is intentionally small because high-school reactions use small integer coefficients.

bounded brute force integer coefficients

Solubility and Activity Rules

Precipitation depends on solubility rules for nitrates, alkali/ammonium salts, halides, sulfates, carbonates, phosphates, and sulfides. Metal displacement compares activity values.

solubility table activity series

Safety Consequences

LabSafetySystem.Apply calculates exposure from fume hood capture, gas trap capture, respirator efficiency, gas severity, and released gas mass. It updates health, credits, incident count, and emergency evacuation state.

hazard model game economy

First-Person Focus

Each frame, the controller raycasts forward from the camera. If the hit object has a parent LabInteractable, the HUD prompt updates and the target receives focus highlighting.

raycast state transition

Enriched X/Y/Z Compound Matrix

X: metal / cation + activity rank
Y: nonmetal / anion family
Z: oxygen count + explicit oxidation state
  |
  v
validate oxidation state
  |
  v
balance charge with GCD
  |
  v
generate formula + molar mass
  |
  v
estimate phase / solubility / colour / hazards
  |
  +-- reviewed override -> confidence Reviewed
  +-- explicit exclusion -> reject candidate
  `-- general rule       -> confidence RuleDerived

The matrix is data-driven through Resources/Chemistry/compound-generation-matrix.json. A literal three-dimensional array would lose oxidation-state and polyatomic-ion information, so the game stores rich coordinate objects while preserving the original X/Y/Z concept.

Chemistry Engine Decision Tree

Vessel additions
  |
  v
Aggregate grams by chemical id
  |
  v
Curated reaction exists?
  |-- yes -> use reviewed ReactionDefinition
  |
  `-- no
      |
      v
      RedoxReactionEngine
        |-- balance electron LCM
        |-- select acid / concentration branch
        `-- otherwise continue
              |
              v
      DynamicReactionEngine
        |-- acid + base
        |-- acid + carbonate / bicarbonate
        |-- acid + sulfide
        |-- ammonium salt + base
        |-- salt + salt precipitation
        |-- metal + salt displacement
        |-- metal + non-oxidising acid
        `-- basic oxide + acid
              |
              v
      CompoundGenerationMatrix
        |-- charge-balanced formula
        |-- phase / solubility / colour
        |-- hazard flags
        |-- Reviewed or RuleDerived confidence
        `-- explicit rejection for unstable candidates
              |
              v
      matched ReactionDefinition or NoMatch
              |
              v
      ReactionConditionEngine
        |-- temperature / volume / molarity / pH
        |-- catalyst / rate / estimated time
        |-- failed constraint -> Blocked
        `-- valid -> stoichiometry + yield
              |
              v
      SynthesizedInventory (optional collection)
        |-- reusable batch + purity + hazards
        |-- JSON persistence
        `-- subtract mass when reused

Safety Flow

1

Gas product

The reaction effect is Gas, so the product formula is looked up in AirborneHazardCatalog.

2

Control check

Fume hood captures 90 percent. Fume hood plus gas trap captures 99.5 percent. Respirator then reduces inhalation exposure where applicable.

3

Consequence

Unsafe exposure reduces health and credits. At zero health, the player is evacuated and returns with 35 health.

4

Feedback

The HUD shows warning text, audio plays a hazard alarm, and the incident remains visible in the safety panel.

These numbers are gameplay values for learning risk-control relationships. They are not medical dose limits.

Folder Structure

chemistryLAB/
|-- Assets/
|   `-- ChemistryLab/
|       |-- Editor/
|       |-- ExternalAssets/
|       |-- Resources/
|       |-- Runtime/
|       `-- Scenes/
|-- BuildReports/
|-- docs/
|   |-- README.md
|   |-- architecture/
|   |-- chemistry/
|   |-- design/
|   |-- gameplay/
|   `-- release/
|-- Packages/
|-- ProjectSettings/
|-- SourceAssets/
`-- README.md

Key Source Files

File Responsibility
Assets/ChemistryLab/Runtime/Bootstrap/DesktopLabGame.cs Game composition, procedural lab construction, vessel state, mission state, runtime smoke test.
Assets/ChemistryLab/Runtime/Chemistry/ChemistryData.cs Chemical definitions, curated reactions, reaction outcomes, simulator entry point.
Assets/ChemistryLab/Runtime/Chemistry/DynamicReactionEngine.cs Species model, reaction-family dispatch, stoichiometry balancing, and activity series.
Assets/ChemistryLab/Runtime/Chemistry/ReactionConditions.cs Per-vessel temperature/volume, molarity and pH estimation, catalyst gates, rate class, time, and yield trends.
Assets/ChemistryLab/Runtime/Chemistry/RedoxReactionEngine.cs Reviewed oxidation-reduction branches and electron GCD/LCM validation.
Assets/ChemistryLab/Runtime/Chemistry/SynthesizedInventory.cs Runtime chemical registry, reusable product batches, exact mass consumption, and persistent JSON storage.
Assets/ChemistryLab/Runtime/Chemistry/CompoundGenerationMatrix.cs JSON-backed element/ion graph, X/Y/Z compound generation, charge balancing, property estimation, confidence, overrides, and exclusions.
Assets/ChemistryLab/Runtime/Safety/LabSafetySystem.cs Chemical hazard classification, airborne hazard profiles, respirator/gas-trap state, exposure consequences.
Assets/ChemistryLab/Runtime/Player/LabInteractions.cs Abstract interactables, concrete interaction objects, first-person movement, raycast focus, hotkeys.
Assets/ChemistryLab/Runtime/UI/DesktopLabHud.cs HUD, inspector, safety panel, pause menu, transient messages, UI button feedback.
Assets/ChemistryLab/Runtime/Audio/DesktopLabAudio.cs Procedural audio generation and playback for UI, movement, reactions, and hazards.
Editor/BuildPipeline/DesktopLabBuild.cs Editor validation, dynamic matrix validation, Windows build report generation.