Claude Code Plugins

Community-maintained marketplace

Feedback

optimization-as-play

@tachyon-beep/skillpacks
1
0

Make optimization itself fun - efficiency puzzles and throughput as gameplay

Install Skill

1Download skill
2Enable skills in Claude

Open claude.ai/settings/capabilities and find the "Skills" section

3Upload to Claude

Click "Upload skill" and select the downloaded ZIP file

Note: Please verify skill by going through its instructions before using it.

SKILL.md

name optimization-as-play
description Make optimization itself fun - efficiency puzzles and throughput as gameplay

Optimization as Play: Making Efficiency The Core Gameplay Loop

Purpose

This skill teaches how to design games where optimization itself is the fun, not a chore you do to progress. Transform production systems, efficiency puzzles, and throughput challenges into engaging player-driven gameplay loops.

Factory games (Factorio, Satisfactory), optimization puzzles (Opus Magnum, SpaceChem), and logistics simulations succeed when players spend hours perfecting their systems for the intrinsic satisfaction of watching efficient production.

This skill is for Wave 2 (Specific Applications) of the systems-as-experience skillpack, building on emergent gameplay foundations.


When to Use This Skill

Use this skill when:

  • Core gameplay loop is building/managing production systems
  • Measurable performance metrics make sense in-world (throughput, efficiency, cost)
  • Multiple valid solutions exist (not one optimal path)
  • Players enjoy efficiency for its own sake (intrinsic motivation)
  • System complexity grows through player mastery (simple → complex)
  • Bottleneck identification is core to gameplay
  • Community can share and compare solutions
  • Visual/spatial problem-solving appeals to target audience

Do NOT use this skill when:

  • Action/reaction gameplay is primary (use real-time challenge design instead)
  • Narrative-driven experience (optimization competes with story pacing)
  • Players must optimize to progress (makes it feel like homework)
  • Only one correct solution exists (reduces to following instructions)
  • Metrics are hidden or meaningless in-world
  • Instant gratification is required (optimization rewards delayed satisfaction)

Key Insight: Optimization-as-play works when it's optional but irresistible. Players choose to optimize because it feels good, not because they're forced to.


Core Philosophy: The Optimization Gameplay Loop

The Fundamental Loop

IDENTIFY BOTTLENECK
       ↓
HYPOTHESIZE SOLUTION
       ↓
   IMPLEMENT
       ↓
    MEASURE
       ↓
   ITERATE
       ↓
(repeat with new bottleneck)

This loop must be:

  1. Visible: Players clearly see what's slow
  2. Fast: Seconds to iterate, not minutes
  3. Satisfying: Improvements feel rewarding
  4. Progressive: Each optimization reveals new bottlenecks
  5. Deep: Mastery unlocks breakthrough solutions

Why Optimization Can Be Fun

Bad optimization (homework):

  • Required to progress
  • One correct answer
  • Math-heavy calculation
  • No visual feedback
  • Linear improvements

Good optimization (play):

  • Optional but compelling
  • Multiple valid approaches
  • Experimental discovery
  • Satisfying visuals/audio
  • Breakthrough moments

The Three Pillars of Optimization-as-Play

  1. Measurement: Players can SEE performance (throughput, efficiency, bottlenecks)
  2. Tradeoffs: Multiple dimensions to optimize (speed vs cost vs space vs power)
  3. Satisfaction: Improvements FEEL good (juice, celebration, visible progress)

SECTION 1: Visible Performance Metrics

The Visibility Principle

"You can't optimize what you can't measure, and players won't measure what you don't show them."

Core Metrics to Visualize

class PerformanceMetrics:
    """
    Essential metrics for optimization gameplay.
    All displayed in real-time, not hidden in menus.
    """
    def __init__(self):
        # Throughput: Items per unit time
        self.items_per_minute = 0.0
        self.target_throughput = 60.0  # Goal to hit

        # Efficiency: % of theoretical maximum
        self.efficiency_percent = 0.0  # 0-100%

        # Bottleneck Status: Where is the slowdown?
        self.bottleneck_type = None  # INPUT_STARVED, OUTPUT_BLOCKED, etc.
        self.bottleneck_location = None  # Which building/node

        # Resource Usage: Cost to run
        self.power_consumption = 0.0
        self.power_budget = 100.0

        # Spatial Efficiency: How compact is layout
        self.footprint_size = 0  # Grid squares used
        self.building_count = 0

        # Utilization: Are buildings idle or running?
        self.avg_utilization = 0.0  # 0-100% average across all buildings

class MetricsDisplay:
    """
    Real-time HUD showing performance metrics.
    Updated every frame for immediate feedback.
    """
    def render(self, metrics):
        # Throughput with color coding
        throughput_color = self.get_color_for_value(
            metrics.items_per_minute,
            metrics.target_throughput
        )
        draw_text(f"{metrics.items_per_minute:.1f}/min",
                  color=throughput_color,
                  size="LARGE")

        # Efficiency percentage
        efficiency_bar(metrics.efficiency_percent)

        # Bottleneck alert (if exists)
        if metrics.bottleneck_type:
            draw_alert(f"BOTTLENECK: {metrics.bottleneck_type}",
                      color=RED,
                      icon=WARNING)
            highlight_location(metrics.bottleneck_location)

        # Resource usage bars
        power_bar(metrics.power_consumption, metrics.power_budget)

        # Utilization indicator
        draw_text(f"Utilization: {metrics.avg_utilization:.0f}%",
                 color=self.get_utilization_color(metrics.avg_utilization))

    def get_color_for_value(self, current, target):
        ratio = current / target if target > 0 else 0
        if ratio >= 0.95:
            return GREEN  # Meeting target
        elif ratio >= 0.7:
            return YELLOW  # Close but sub-optimal
        else:
            return RED  # Significant underperformance

Throughput Visualization: Flow Indicators

class ConveyorBelt:
    """
    Visual conveyor that shows item flow rate.
    Players should SEE throughput, not just read numbers.
    """
    def __init__(self, start, end, max_throughput=60):
        self.start = start
        self.end = end
        self.max_throughput = max_throughput  # items/min
        self.current_throughput = 0.0
        self.items_in_transit = []

        # Visual feedback
        self.flow_animation_speed = 1.0
        self.color = WHITE

    def update(self, dt):
        # Calculate actual throughput
        self.current_throughput = self.measure_throughput()

        # Update visual feedback based on throughput
        utilization = self.current_throughput / self.max_throughput

        # Color coding
        if utilization > 0.9:
            self.color = GREEN  # Running hot
        elif utilization > 0.6:
            self.color = YELLOW  # Decent flow
        elif utilization > 0.2:
            self.color = ORANGE  # Weak flow
        else:
            self.color = RED  # Barely moving

        # Animation speed matches throughput
        self.flow_animation_speed = utilization * 2.0

        # Move items along belt
        for item in self.items_in_transit:
            item.position += self.flow_animation_speed * dt

    def render(self):
        # Draw belt with color indicating flow rate
        draw_line(self.start, self.end, color=self.color, width=4)

        # Draw items in transit
        for item in self.items_in_transit:
            draw_item(item)

        # Draw throughput counter
        counter_position = midpoint(self.start, self.end)
        draw_text(f"{self.current_throughput:.0f}/min",
                 position=counter_position,
                 background=BLACK_ALPHA,
                 color=self.color)

Building Status Indicators

class ProductionBuilding:
    """
    Building with clear visual status indicators.
    Player should instantly know if building is:
    - Running optimally (GREEN)
    - Input-starved (RED, no inputs available)
    - Output-blocked (YELLOW, can't output products)
    - Powered off (GRAY)
    """

    class Status(Enum):
        OPTIMAL = "OPTIMAL"
        INPUT_STARVED = "INPUT_STARVED"
        OUTPUT_BLOCKED = "OUTPUT_BLOCKED"
        POWER_INSUFFICIENT = "POWER_INSUFFICIENT"
        IDLE = "IDLE"

    def __init__(self, recipe):
        self.recipe = recipe
        self.input_buffer = {}
        self.output_buffer = {}
        self.status = Status.IDLE
        self.utilization = 0.0  # 0-1 ratio

    def update(self, dt):
        # Determine status based on state
        if not self.has_power():
            self.status = Status.POWER_INSUFFICIENT
            self.utilization = 0.0
        elif not self.has_required_inputs():
            self.status = Status.INPUT_STARVED
            self.utilization = 0.0
        elif self.is_output_full():
            self.status = Status.OUTPUT_BLOCKED
            self.utilization = 0.0
        else:
            self.status = Status.OPTIMAL
            self.utilization = 1.0
            self.produce(dt)

    def render(self):
        # Base building sprite
        draw_building(self.sprite)

        # Status indicator (prominent visual)
        status_color = {
            Status.OPTIMAL: GREEN,
            Status.INPUT_STARVED: RED,
            Status.OUTPUT_BLOCKED: YELLOW,
            Status.POWER_INSUFFICIENT: DARK_RED,
            Status.IDLE: GRAY
        }[self.status]

        # Draw status ring around building
        draw_ring(self.position,
                 radius=self.size * 1.2,
                 color=status_color,
                 width=4,
                 pulsate=(self.status != Status.OPTIMAL))

        # Draw utilization percentage
        draw_text(f"{self.utilization * 100:.0f}%",
                 position=self.position + Vector2(0, -20),
                 color=status_color)

        # Draw status icon
        status_icon = {
            Status.OPTIMAL: ICON_CHECKMARK,
            Status.INPUT_STARVED: ICON_ARROW_IN_RED,
            Status.OUTPUT_BLOCKED: ICON_ARROW_OUT_YELLOW,
            Status.POWER_INSUFFICIENT: ICON_LIGHTNING_OFF,
            Status.IDLE: ICON_PAUSE
        }[self.status]
        draw_icon(status_icon, self.position + Vector2(0, 20))

Production Dashboard

class ProductionDashboard:
    """
    Central analytics panel showing factory-wide performance.
    Updated in real-time so players see immediate effect of changes.
    """
    def __init__(self, factory):
        self.factory = factory
        self.history = []  # Time-series data for graphs

    def update(self, dt):
        # Collect current metrics
        snapshot = {
            'timestamp': time.now(),
            'throughput': self.factory.measure_total_throughput(),
            'efficiency': self.factory.calculate_efficiency(),
            'bottlenecks': self.factory.identify_bottlenecks(),
            'power_usage': self.factory.total_power_consumption(),
            'utilization': self.factory.average_utilization()
        }
        self.history.append(snapshot)

        # Keep last 5 minutes of history
        cutoff = time.now() - timedelta(minutes=5)
        self.history = [s for s in self.history if s['timestamp'] > cutoff]

    def render(self):
        # Throughput graph (last 5 minutes)
        draw_graph(
            data=[s['throughput'] for s in self.history],
            title="Throughput (items/min)",
            color=GREEN,
            show_target=True
        )

        # Efficiency meter
        current_efficiency = self.history[-1]['efficiency']
        draw_radial_meter(
            value=current_efficiency,
            label="Efficiency",
            color_gradient=[RED, YELLOW, GREEN]
        )

        # Bottleneck list (top 3 worst)
        bottlenecks = self.history[-1]['bottlenecks']
        draw_bottleneck_list(bottlenecks[:3])

        # Resource usage bars
        power_usage = self.history[-1]['power_usage']
        draw_resource_bar("Power", power_usage, self.factory.power_capacity)

        # Overall utilization
        utilization = self.history[-1]['utilization']
        draw_text(f"Factory Utilization: {utilization:.0f}%",
                 size=LARGE,
                 color=GREEN if utilization > 80 else YELLOW)

Example: Full Visibility System

class FactoryGame:
    """
    Complete factory game with full metric visibility.
    Every optimization decision is informed by clear data.
    """
    def __init__(self):
        self.buildings = []
        self.conveyors = []
        self.metrics = PerformanceMetrics()
        self.dashboard = ProductionDashboard(self)

    def update(self, dt):
        # Update all production
        for building in self.buildings:
            building.update(dt)
        for conveyor in self.conveyors:
            conveyor.update(dt)

        # Update metrics
        self.metrics.items_per_minute = self.measure_total_throughput()
        self.metrics.efficiency_percent = self.calculate_efficiency() * 100
        self.metrics.bottleneck_type, self.metrics.bottleneck_location = \
            self.identify_primary_bottleneck()
        self.metrics.power_consumption = self.total_power_consumption()
        self.metrics.footprint_size = self.calculate_footprint()
        self.metrics.building_count = len(self.buildings)
        self.metrics.avg_utilization = self.average_utilization() * 100

        # Update dashboard
        self.dashboard.update(dt)

    def render(self):
        # Render all buildings with status indicators
        for building in self.buildings:
            building.render()

        # Render conveyors with flow visualization
        for conveyor in self.conveyors:
            conveyor.render()

        # Render metrics HUD
        MetricsDisplay().render(self.metrics)

        # Render dashboard (if open)
        if player.dashboard_open:
            self.dashboard.render()

    def identify_primary_bottleneck(self):
        """
        Find the worst bottleneck in the factory.
        Returns (type, location) tuple.
        """
        worst_building = None
        worst_utilization = 1.0

        for building in self.buildings:
            if building.utilization < worst_utilization:
                worst_utilization = building.utilization
                worst_building = building

        if worst_building and worst_utilization < 0.9:
            return (worst_building.status, worst_building.position)
        else:
            return (None, None)

SECTION 2: Bottleneck Identification as Core Mechanic

The Bottleneck Game

"Factory optimization is bottleneck whack-a-mole: fix one, another appears. This IS the game."

The most engaging optimization games make bottleneck discovery the primary skill.

What Makes a Good Bottleneck System

  1. Visible: Bottlenecks are highlighted, not hidden
  2. Progressive: Fixing one reveals the next
  3. Cascading: Bottleneck shifts as you optimize
  4. Multiple Types: Input-starved, output-blocked, under-powered, poor layout
  5. Solvable: Clear cause → clear solution

Bottleneck Detection System

class BottleneckDetector:
    """
    Analyzes production chain to find weakest links.
    Highlights problems for player to solve.
    """

    class BottleneckType(Enum):
        INPUT_STARVED = "Not enough input materials"
        OUTPUT_BLOCKED = "Output buffer full, can't produce more"
        THROUGHPUT_LIMITED = "Building capacity too low"
        TRANSPORT_BOTTLENECK = "Conveyor can't handle flow rate"
        POWER_INSUFFICIENT = "Not enough power to run at full capacity"
        RATIO_IMBALANCE = "Production doesn't match consumption ratios"

    def __init__(self, factory):
        self.factory = factory
        self.bottlenecks = []

    def analyze(self):
        """
        Scan entire factory for bottlenecks.
        Returns list sorted by severity (worst first).
        """
        self.bottlenecks = []

        # Check each building
        for building in self.factory.buildings:
            severity = self.calculate_bottleneck_severity(building)
            if severity > 0.1:  # Threshold: 10% underperformance
                bottleneck = {
                    'building': building,
                    'type': self.diagnose_bottleneck_type(building),
                    'severity': severity,  # 0-1, higher = worse
                    'suggested_fix': self.suggest_solution(building)
                }
                self.bottlenecks.append(bottleneck)

        # Check conveyors
        for conveyor in self.factory.conveyors:
            if conveyor.is_bottleneck():
                self.bottlenecks.append({
                    'conveyor': conveyor,
                    'type': BottleneckType.TRANSPORT_BOTTLENECK,
                    'severity': conveyor.congestion_ratio(),
                    'suggested_fix': "Upgrade conveyor or add parallel belt"
                })

        # Sort by severity
        self.bottlenecks.sort(key=lambda b: b['severity'], reverse=True)
        return self.bottlenecks

    def calculate_bottleneck_severity(self, building):
        """
        How badly is this building underperforming?
        0.0 = running optimally
        1.0 = completely blocked/starved
        """
        if building.status == Building.Status.OPTIMAL:
            return 0.0
        elif building.status == Building.Status.IDLE:
            return 0.05  # Minor issue
        else:
            # Measure actual throughput vs theoretical max
            actual = building.current_throughput
            theoretical = building.max_throughput
            return 1.0 - (actual / theoretical)

    def diagnose_bottleneck_type(self, building):
        """
        Determine WHY building is bottlenecked.
        """
        if building.status == Building.Status.INPUT_STARVED:
            return BottleneckType.INPUT_STARVED
        elif building.status == Building.Status.OUTPUT_BLOCKED:
            return BottleneckType.OUTPUT_BLOCKED
        elif building.status == Building.Status.POWER_INSUFFICIENT:
            return BottleneckType.POWER_INSUFFICIENT
        elif building.current_throughput < building.max_throughput * 0.5:
            return BottleneckType.THROUGHPUT_LIMITED
        else:
            return BottleneckType.RATIO_IMBALANCE

    def suggest_solution(self, building):
        """
        Give player actionable hint about how to fix bottleneck.
        """
        bottleneck_type = self.diagnose_bottleneck_type(building)

        suggestions = {
            BottleneckType.INPUT_STARVED:
                "Add more input producers or faster conveyors",
            BottleneckType.OUTPUT_BLOCKED:
                "Add more consumers or larger output buffers",
            BottleneckType.THROUGHPUT_LIMITED:
                "Build additional buildings or upgrade throughput",
            BottleneckType.POWER_INSUFFICIENT:
                "Build more power generators",
            BottleneckType.RATIO_IMBALANCE:
                f"Ratio issue: needs {building.recipe.optimal_ratio}"
        }

        return suggestions.get(bottleneck_type, "Optimize this building")

Visual Bottleneck Highlighting

class BottleneckVisualizer:
    """
    Makes bottlenecks OBVIOUS through visual cues.
    Player should instantly see problem areas.
    """
    def __init__(self, detector):
        self.detector = detector

    def render(self):
        bottlenecks = self.detector.analyze()

        for bottleneck in bottlenecks[:5]:  # Show top 5 worst
            severity = bottleneck['severity']

            if 'building' in bottleneck:
                location = bottleneck['building'].position
            else:
                location = bottleneck['conveyor'].midpoint()

            # Pulsating alert icon
            self.draw_alert_marker(location, severity)

            # Color-coded severity
            color = self.get_severity_color(severity)

            # Draw problem description
            draw_tooltip(
                position=location + Vector2(0, -40),
                text=f"{bottleneck['type'].value}\n{bottleneck['suggested_fix']}",
                background_color=color + ALPHA(0.8)
            )

            # Highlight affected area
            draw_highlight_circle(location,
                                 radius=50,
                                 color=color,
                                 pulse_speed=severity * 2)

    def get_severity_color(self, severity):
        """Gradient from yellow (minor) to red (critical)"""
        if severity > 0.7:
            return RED
        elif severity > 0.4:
            return ORANGE
        else:
            return YELLOW

    def draw_alert_marker(self, position, severity):
        """Animated warning icon that pulses based on severity"""
        pulse_scale = 1.0 + math.sin(time.now() * severity * 5) * 0.2
        draw_icon(ICON_WARNING,
                 position=position,
                 scale=pulse_scale,
                 color=self.get_severity_color(severity))

Cascading Bottleneck System

class CascadingBottlenecks:
    """
    Demonstrates how fixing one bottleneck reveals the next.
    This creates the core optimization gameplay loop.
    """
    def __init__(self):
        self.production_chain = [
            # Simple chain: Miner → Smelter → Assembler
            Building("Miner", max_throughput=30),
            Building("Smelter", max_throughput=20),  # INITIAL BOTTLENECK
            Building("Assembler", max_throughput=15)
        ]

    def simulate_optimization_progression(self):
        """
        Show how bottleneck shifts as player optimizes.
        """
        print("INITIAL STATE:")
        self.analyze_chain()
        # Output: "Bottleneck: Smelter (20/min limiting 30/min miner)"

        print("\nPLAYER ACTION: Upgrade Smelter to 40/min")
        self.production_chain[1].max_throughput = 40
        self.analyze_chain()
        # Output: "Bottleneck: Miner (30/min limiting 40/min smelter)"
        # Bottleneck SHIFTED to Miner!

        print("\nPLAYER ACTION: Add second Miner")
        self.production_chain.insert(0, Building("Miner", max_throughput=30))
        self.analyze_chain()
        # Output: "Bottleneck: Assembler (15/min limiting 60/min input)"
        # Now Assembler is the limit!

        print("\nPLAYER ACTION: Build 4 Assemblers in parallel")
        for i in range(3):
            self.production_chain.append(Building("Assembler", max_throughput=15))
        self.analyze_chain()
        # Output: "No bottlenecks! Factory running at full capacity"

    def analyze_chain(self):
        throughputs = [b.max_throughput for b in self.production_chain]
        bottleneck = min(throughputs)
        bottleneck_building = self.production_chain[throughputs.index(bottleneck)]
        print(f"Bottleneck: {bottleneck_building.name} ({bottleneck}/min)")

Example: Factorio-Style Ratio Problems

class RecipeRatios:
    """
    Perfect ratio calculation - the heart of factory optimization.
    Example: Iron smelting requires 3 miners per 2 smelters
    """
    def __init__(self):
        self.recipes = {
            'iron_plate': {
                'inputs': {'iron_ore': 1},
                'outputs': {'iron_plate': 1},
                'crafting_time': 3.5,  # seconds
                'producers': ['stone_furnace']
            },
            'gear_wheel': {
                'inputs': {'iron_plate': 2},
                'outputs': {'gear_wheel': 1},
                'crafting_time': 0.5,
                'producers': ['assembling_machine']
            }
        }

    def calculate_optimal_ratio(self, recipe_name, target_throughput):
        """
        Calculate how many buildings needed for target throughput.

        Example:
        - Want 60 iron plates/min
        - Each furnace produces 1 plate per 3.5 seconds = 17.14/min
        - Need 60 / 17.14 = 3.5 furnaces (round up to 4)
        """
        recipe = self.recipes[recipe_name]
        output_per_building = 60.0 / recipe['crafting_time']  # items per minute
        buildings_needed = target_throughput / output_per_building
        return math.ceil(buildings_needed)

    def detect_ratio_imbalance(self, factory):
        """
        Identify where production doesn't match consumption.
        """
        imbalances = []

        for resource_type in factory.all_resource_types():
            production_rate = factory.measure_production(resource_type)
            consumption_rate = factory.measure_consumption(resource_type)

            if production_rate < consumption_rate * 0.95:
                # Under-producing
                imbalances.append({
                    'resource': resource_type,
                    'problem': 'UNDER_PRODUCING',
                    'production': production_rate,
                    'consumption': consumption_rate,
                    'deficit': consumption_rate - production_rate
                })
            elif production_rate > consumption_rate * 1.1:
                # Over-producing (wasteful)
                imbalances.append({
                    'resource': resource_type,
                    'problem': 'OVER_PRODUCING',
                    'production': production_rate,
                    'consumption': consumption_rate,
                    'surplus': production_rate - consumption_rate
                })

        return imbalances

SECTION 3: Multiple Valid Solutions (Tradeoff Design)

The Tradeoff Principle

"One correct answer = following instructions. Multiple valid approaches = optimization gameplay."

Core Tradeoff Dimensions

class OptimizationTradeoffs:
    """
    Four primary dimensions players can optimize.
    Different players will prioritize different dimensions.
    """
    def __init__(self):
        self.dimensions = {
            'throughput': 0.0,    # Items per minute (SPEED)
            'cost': 0.0,          # Resources spent (ECONOMY)
            'footprint': 0.0,     # Space used (COMPACTNESS)
            'power': 0.0          # Power consumption (EFFICIENCY)
        }

    def evaluate_design(self, factory_design):
        """
        Score a factory design across all dimensions.
        No single "best" design - tradeoffs exist.
        """
        return {
            'throughput': factory_design.measure_throughput(),
            'cost': factory_design.calculate_total_cost(),
            'footprint': factory_design.calculate_footprint(),
            'power': factory_design.total_power_consumption()
        }

    def compare_designs(self, design_a, design_b):
        """
        Show how two designs make different tradeoffs.

        Example output:
        Design A: High throughput, high cost, large footprint, high power
        Design B: Medium throughput, low cost, compact, low power

        Winner depends on player priorities!
        """
        scores_a = self.evaluate_design(design_a)
        scores_b = self.evaluate_design(design_b)

        comparison = {}
        for dimension in self.dimensions:
            if scores_a[dimension] > scores_b[dimension]:
                comparison[dimension] = "A wins"
            elif scores_b[dimension] > scores_a[dimension]:
                comparison[dimension] = "B wins"
            else:
                comparison[dimension] = "Tie"

        return comparison

Example: Speed vs Cost Tradeoff

class FactoryDesigns:
    """
    Two valid solutions to same problem: produce 60 circuits/min.
    Different players will prefer different approaches.
    """

    def speed_focused_design(self):
        """
        FAST but EXPENSIVE.
        Use advanced buildings with high throughput.
        """
        return {
            'buildings': [
                Building('advanced_assembler', throughput=30, cost=500, power=10),
                Building('advanced_assembler', throughput=30, cost=500, power=10)
            ],
            'total_throughput': 60,
            'total_cost': 1000,
            'total_power': 20,
            'footprint': 4  # 2 buildings x 2 tiles each
        }

    def cost_focused_design(self):
        """
        SLOW but CHEAP.
        Use basic buildings in larger quantity.
        """
        return {
            'buildings': [
                Building('basic_assembler', throughput=10, cost=100, power=2),
                Building('basic_assembler', throughput=10, cost=100, power=2),
                Building('basic_assembler', throughput=10, cost=100, power=2),
                Building('basic_assembler', throughput=10, cost=100, power=2),
                Building('basic_assembler', throughput=10, cost=100, power=2),
                Building('basic_assembler', throughput=10, cost=100, power=2)
            ],
            'total_throughput': 60,
            'total_cost': 600,
            'total_power': 12,
            'footprint': 12  # 6 buildings x 2 tiles each
        }

    def compare(self):
        """
        Speed design: 40% more expensive, 67% less power, 67% smaller footprint
        Cost design: 40% cheaper, 67% more power, 3x larger footprint

        Both achieve same throughput!
        Player choice depends on constraints (money? space? power?)
        """
        pass

Spatial Optimization: Layout Tradeoffs

class LayoutOptimization:
    """
    Space is a resource. Compact layouts vs sprawling layouts.
    """

    def compact_design(self):
        """
        TIGHT but INFLEXIBLE.
        Every tile used efficiently, but hard to expand.
        """
        return {
            'layout_style': 'compact',
            'footprint': 20,  # 4x5 grid
            'conveyor_length': 15,  # Short paths
            'expandability': 'LOW',  # No room to grow
            'visual_clarity': 'LOW',  # Hard to see what's happening
            'throughput': 60
        }

    def sprawling_design(self):
        """
        LOOSE but FLEXIBLE.
        Easy to understand and expand, but uses more space.
        """
        return {
            'layout_style': 'sprawling',
            'footprint': 60,  # 10x6 grid
            'conveyor_length': 35,  # Longer paths
            'expandability': 'HIGH',  # Room to add more
            'visual_clarity': 'HIGH',  # Easy to see flow
            'throughput': 60
        }

    def modular_design(self):
        """
        MODULAR but COMPLEX.
        Repeatable blueprints that tile together.
        """
        return {
            'layout_style': 'modular',
            'footprint': 40,  # 8x5 grid (4 modules of 4x2.5)
            'conveyor_length': 25,
            'expandability': 'MEDIUM',  # Can tile modules
            'visual_clarity': 'MEDIUM',  # Clear within module
            'throughput': 60,
            'reusability': 'HIGH'  # Can copy/paste module
        }

Challenge System with Multiple Solutions

class OptimizationChallenge:
    """
    Puzzle-style challenge with multiple valid solutions.
    Players can optimize for different dimensions.
    """
    def __init__(self, name, constraints):
        self.name = name
        self.constraints = constraints
        self.leaderboards = {
            'speed': [],      # Fastest throughput
            'cost': [],       # Cheapest solution
            'compact': [],    # Smallest footprint
            'power': [],      # Lowest power usage
            'balanced': []    # Best overall score
        }

    def evaluate_solution(self, factory):
        """
        Grade solution across all dimensions.
        """
        # Measure performance
        throughput = factory.measure_throughput()
        cost = factory.calculate_cost()
        footprint = factory.calculate_footprint()
        power = factory.power_consumption()

        # Check constraints met
        meets_constraints = (
            throughput >= self.constraints['min_throughput'] and
            cost <= self.constraints['max_cost'] and
            footprint <= self.constraints['max_footprint'] and
            power <= self.constraints['max_power']
        )

        if not meets_constraints:
            return {'valid': False, 'reason': 'Constraints not met'}

        # Calculate dimension-specific scores
        scores = {
            'speed_score': throughput,  # Higher is better
            'cost_score': 1.0 / cost,   # Lower cost is better
            'compact_score': 1.0 / footprint,
            'power_score': 1.0 / power,
            'balanced_score': self.calculate_balanced_score(
                throughput, cost, footprint, power
            )
        }

        return {'valid': True, 'scores': scores}

    def calculate_balanced_score(self, throughput, cost, footprint, power):
        """
        Weighted average across all dimensions.
        Rewards well-rounded solutions.
        """
        # Normalize each dimension to 0-1 scale
        normalized = {
            'throughput': throughput / self.constraints['min_throughput'],
            'cost': self.constraints['max_cost'] / cost,
            'footprint': self.constraints['max_footprint'] / footprint,
            'power': self.constraints['max_power'] / power
        }

        # Equal weighting (could adjust for game balance)
        weights = {'throughput': 0.4, 'cost': 0.2, 'footprint': 0.2, 'power': 0.2}

        total = sum(normalized[dim] * weights[dim] for dim in weights)
        return total

# Example challenge
circuit_production_challenge = OptimizationChallenge(
    name="Circuit Production Challenge",
    constraints={
        'min_throughput': 60,   # Must produce at least 60/min
        'max_cost': 2000,       # Can't spend more than 2000 resources
        'max_footprint': 50,    # Can't use more than 50 tiles
        'max_power': 30         # Can't exceed 30 power
    }
)

# Different players will optimize for different dimensions:
# - Speedrunner: Max throughput, ignore cost
# - Minimalist: Smallest footprint, accept lower throughput
# - Economist: Cheapest solution, maximize cost efficiency
# - Engineer: Balanced solution across all dimensions

SECTION 4: Satisfying Feedback (The Juice)

The Satisfaction Principle

"Optimization must FEEL good. Visual, audio, and numeric feedback make improvements satisfying."

Visual Feedback: Flow Animations

class FlowAnimation:
    """
    Make production VISIBLE and SATISFYING to watch.
    """
    def __init__(self, conveyor):
        self.conveyor = conveyor
        self.particles = []

    def update(self, dt):
        # Spawn particles based on throughput
        spawn_rate = self.conveyor.current_throughput / 60.0  # per second
        if random.random() < spawn_rate * dt:
            self.spawn_particle()

        # Move particles along belt
        for particle in self.particles:
            particle.position += self.conveyor.direction * dt * 100

            # Arrived at destination?
            if particle.position >= self.conveyor.end:
                self.particles.remove(particle)
                self.spawn_arrival_effect()

    def spawn_particle(self):
        """Create visible item moving along belt"""
        particle = {
            'position': self.conveyor.start,
            'sprite': self.get_item_sprite(),
            'speed': 100  # pixels per second
        }
        self.particles.append(particle)

    def spawn_arrival_effect(self):
        """Satisfying 'pop' when item reaches destination"""
        spawn_particle_effect(
            position=self.conveyor.end,
            particle_count=5,
            color=YELLOW,
            lifetime=0.3
        )
        play_sound("item_received", volume=0.5)

    def render(self):
        # Draw all items in transit
        for particle in self.particles:
            draw_sprite(particle['sprite'], particle['position'])

Audio Feedback: Production Sounds

class ProductionAudio:
    """
    Sound design that reflects factory efficiency.
    Fast factory sounds busy and productive.
    Slow factory sounds sluggish.
    """
    def __init__(self, factory):
        self.factory = factory
        self.sound_pools = {
            'machine_hum': AudioPool('machine_hum.wav', max_instances=10),
            'conveyor_move': AudioPool('conveyor.wav', max_instances=5),
            'item_process': AudioPool('process.wav', max_instances=20)
        }

    def update(self, dt):
        # Adjust ambient factory sound based on total throughput
        total_throughput = self.factory.measure_total_throughput()
        ambient_intensity = min(1.0, total_throughput / 100.0)

        self.sound_pools['machine_hum'].set_volume(ambient_intensity)
        self.sound_pools['machine_hum'].set_pitch(0.8 + ambient_intensity * 0.4)

        # Play processing sounds based on building activity
        for building in self.factory.buildings:
            if building.just_produced_item():
                self.sound_pools['item_process'].play(
                    volume=building.utilization,
                    pitch=random.uniform(0.9, 1.1)
                )

        # Conveyor sounds based on flow rate
        for conveyor in self.factory.conveyors:
            if conveyor.current_throughput > 0:
                volume = conveyor.current_throughput / conveyor.max_throughput
                self.sound_pools['conveyor_move'].play(
                    volume=volume * 0.3,
                    pitch=0.8 + volume * 0.4,
                    loop=True
                )

Milestone Celebrations

class MilestoneSystem:
    """
    Celebrate achievement of production goals.
    Makes optimization feel rewarding.
    """
    def __init__(self):
        self.milestones = [
            {'threshold': 10, 'name': 'First Production', 'reward': 'Unlock automation'},
            {'threshold': 60, 'name': 'One Per Second', 'reward': 'Unlock advanced buildings'},
            {'threshold': 300, 'name': 'Five Per Second', 'reward': 'Unlock logistics'},
            {'threshold': 1000, 'name': 'Industrial Scale', 'reward': 'Unlock megafactory tools'},
            {'threshold': 6000, 'name': 'One Hundred Per Second', 'reward': 'Unlock planetary production'}
        ]
        self.achieved = set()

    def check_milestones(self, current_throughput):
        """
        Check if player hit new milestone.
        """
        for milestone in self.milestones:
            if milestone['threshold'] not in self.achieved:
                if current_throughput >= milestone['threshold']:
                    self.celebrate_milestone(milestone)
                    self.achieved.add(milestone['threshold'])

    def celebrate_milestone(self, milestone):
        """
        Big satisfying celebration when milestone hit.
        """
        # Visual celebration
        spawn_fireworks(count=20, duration=3.0)
        show_banner(
            text=f"MILESTONE: {milestone['name']}",
            subtext=f"Producing {milestone['threshold']} items/min!",
            duration=5.0,
            color=GOLD
        )

        # Audio celebration
        play_sound("milestone_fanfare")

        # Reward
        unlock_feature(milestone['reward'])
        show_notification(f"Unlocked: {milestone['reward']}")

        # Achievement tracking
        save_achievement(milestone['name'], timestamp=now())

Real-Time Statistics Dashboard

class StatisticsDashboard:
    """
    Detailed analytics that update in real-time.
    Seeing numbers go up is satisfying.
    """
    def __init__(self, factory):
        self.factory = factory
        self.stats = {
            'items_produced_total': 0,
            'items_produced_this_minute': 0,
            'efficiency_current': 0.0,
            'efficiency_all_time_best': 0.0,
            'bottleneck_count': 0,
            'uptime_percentage': 100.0
        }

    def update(self, dt):
        # Update all statistics
        self.stats['items_produced_total'] = self.factory.lifetime_production
        self.stats['items_produced_this_minute'] = self.factory.recent_production

        current_efficiency = self.factory.calculate_efficiency()
        self.stats['efficiency_current'] = current_efficiency

        if current_efficiency > self.stats['efficiency_all_time_best']:
            self.stats['efficiency_all_time_best'] = current_efficiency
            self.celebrate_new_record()

        self.stats['bottleneck_count'] = len(self.factory.identify_bottlenecks())
        self.stats['uptime_percentage'] = self.factory.calculate_uptime()

    def render(self):
        """
        Display statistics with emphasis on improvements.
        """
        # Total production (big number = satisfying)
        draw_text(f"{self.stats['items_produced_total']:,}",
                 size=HUGE,
                 color=GREEN,
                 label="Total Produced")

        # Current throughput with sparkline
        draw_metric_with_sparkline(
            value=self.stats['items_produced_this_minute'],
            label="Items/Min",
            history=self.factory.throughput_history,
            color=BLUE
        )

        # Efficiency with comparison to best
        efficiency_pct = self.stats['efficiency_current'] * 100
        best_pct = self.stats['efficiency_all_time_best'] * 100
        draw_comparison_metric(
            current=efficiency_pct,
            best=best_pct,
            label="Efficiency",
            format="{:.1f}%"
        )

        # Bottleneck count (lower is better)
        color = GREEN if self.stats['bottleneck_count'] == 0 else RED
        draw_text(f"{self.stats['bottleneck_count']} Bottlenecks",
                 color=color)

    def celebrate_new_record(self):
        """Called when player beats their efficiency record"""
        show_notification("NEW RECORD EFFICIENCY!", color=GOLD)
        play_sound("record_broken")

Comparison Visualization

class BeforeAfterComparison:
    """
    Show player the impact of their optimization.
    Visual proof of improvement is satisfying.
    """
    def __init__(self):
        self.snapshots = {}

    def take_snapshot(self, label):
        """Capture current factory state"""
        self.snapshots[label] = {
            'timestamp': now(),
            'throughput': factory.measure_throughput(),
            'efficiency': factory.calculate_efficiency(),
            'cost': factory.calculate_cost(),
            'footprint': factory.calculate_footprint(),
            'screenshot': factory.capture_screenshot()
        }

    def show_comparison(self, before_label, after_label):
        """
        Side-by-side comparison showing improvement.
        """
        before = self.snapshots[before_label]
        after = self.snapshots[after_label]

        # Visual comparison
        draw_side_by_side(before['screenshot'], after['screenshot'])

        # Metric improvements
        improvements = {
            'throughput': {
                'before': before['throughput'],
                'after': after['throughput'],
                'change': after['throughput'] - before['throughput'],
                'percent': (after['throughput'] / before['throughput'] - 1) * 100
            },
            'efficiency': {
                'before': before['efficiency'],
                'after': after['efficiency'],
                'change': after['efficiency'] - before['efficiency'],
                'percent': (after['efficiency'] / before['efficiency'] - 1) * 100
            }
        }

        # Show improvements with big positive numbers
        for metric, data in improvements.items():
            draw_improvement_card(
                metric=metric,
                before=data['before'],
                after=data['after'],
                change=data['change'],
                percent_change=data['percent']
            )

# Usage
comparison = BeforeAfterComparison()
comparison.take_snapshot("initial_build")
# ... player optimizes ...
comparison.take_snapshot("after_optimization")
comparison.show_comparison("initial_build", "after_optimization")
# Shows: "Throughput improved by 150%! 🎉"

SECTION 5: Progressive Complexity

The Learning Curve Principle

"Start stupidly simple. Add complexity as player masters current level."

Tutorial Progression

class TutorialProgression:
    """
    Introduce optimization concepts gradually.
    Each stage builds on previous understanding.
    """
    def __init__(self):
        self.stages = [
            self.stage_1_single_chain(),
            self.stage_2_bottleneck_intro(),
            self.stage_3_parallel_production(),
            self.stage_4_ratios(),
            self.stage_5_multi_stage(),
            self.stage_6_logistics(),
            self.stage_7_megafactory()
        ]
        self.current_stage = 0

    def stage_1_single_chain(self):
        """
        STAGE 1: Single Production Chain
        Goal: Learn basic building → conveyor → building flow
        """
        return {
            'name': 'Your First Factory',
            'unlocked_buildings': ['miner', 'smelter', 'chest'],
            'unlocked_mechanics': ['conveyors', 'placing_buildings'],
            'goal': 'Produce 10 iron plates',
            'complexity': 'MINIMAL',
            'lesson': 'Production flows from source → processor → output',
            'example_solution': lambda: [
                Place('miner', (0, 0)),
                Place('conveyor', (1, 0)),
                Place('smelter', (2, 0)),
                Place('conveyor', (3, 0)),
                Place('chest', (4, 0))
            ]
        }

    def stage_2_bottleneck_intro(self):
        """
        STAGE 2: First Bottleneck
        Goal: Identify and fix a bottleneck
        """
        return {
            'name': 'Finding the Slowdown',
            'unlocked_buildings': ['miner', 'smelter'],
            'unlocked_mechanics': ['throughput_display', 'status_indicators'],
            'starting_setup': [
                # Pre-placed factory with obvious bottleneck
                Building('miner', throughput=30),  # Fast
                Building('smelter', throughput=10)  # BOTTLENECK (slow)
            ],
            'goal': 'Increase output to 30 plates/min',
            'complexity': 'LOW',
            'lesson': 'Bottleneck = slowest link. Fix it to improve overall throughput',
            'hint': 'The smelter can only handle 10/min but the miner produces 30/min'
        }

    def stage_3_parallel_production(self):
        """
        STAGE 3: Parallel Production
        Goal: Scale up by building in parallel
        """
        return {
            'name': 'Scaling Up',
            'unlocked_mechanics': ['splitter', 'merger'],
            'goal': 'Produce 100 iron plates/min',
            'complexity': 'MEDIUM',
            'lesson': 'When one building isn\'t enough, build multiple in parallel',
            'example_solution': lambda: [
                # 3 miners → splitter → 3 smelters (parallel processing)
                Place('miner', (0, 0)),
                Place('miner', (0, 1)),
                Place('miner', (0, 2)),
                Place('splitter_3way', (1, 1)),
                Place('smelter', (2, 0)),
                Place('smelter', (2, 1)),
                Place('smelter', (2, 2)),
                Place('merger_3way', (3, 1))
            ]
        }

    def stage_4_ratios(self):
        """
        STAGE 4: Perfect Ratios
        Goal: Discover optimal building ratios
        """
        return {
            'name': 'Perfect Balance',
            'unlocked_mechanics': ['ratio_calculator'],
            'goal': 'Build factory with 100% efficiency (no idle buildings)',
            'complexity': 'MEDIUM',
            'lesson': 'Perfect ratios mean no buildings are idle or starved',
            'teaching_moment': '''
                Given:
                - 1 Miner produces 30 ore/min
                - 1 Smelter needs 20 ore/min

                Optimal ratio = 2 miners : 3 smelters (60 ore production, 60 ore consumption)
            '''
        }

    def stage_5_multi_stage(self):
        """
        STAGE 5: Multi-Stage Production
        Goal: Chain multiple recipes together
        """
        return {
            'name': 'Production Chains',
            'unlocked_buildings': ['assembler'],
            'unlocked_recipes': ['gear_wheel', 'circuit'],
            'goal': 'Produce 60 circuits/min (requires iron plates + copper wire)',
            'complexity': 'HIGH',
            'lesson': 'Complex products require managing multiple input chains',
            'example_chain': lambda: {
                'iron_ore': ['mine'] → ['smelt'] → ['iron_plates'],
                'copper_ore': ['mine'] → ['smelt'] → ['copper_plates'] → ['wire_machine'] → ['copper_wire'],
                'circuit': ['iron_plates' + 'copper_wire'] → ['assemble'] → ['circuit']
            }
        }

    def stage_6_logistics(self):
        """
        STAGE 6: Long-Distance Logistics
        Goal: Transport resources across map
        """
        return {
            'name': 'Supply Chains',
            'unlocked_buildings': ['train', 'train_station'],
            'unlocked_mechanics': ['logistics_network'],
            'goal': 'Transport iron from distant mine to factory',
            'complexity': 'HIGH',
            'lesson': 'Large-scale production requires logistics infrastructure',
            'new_challenges': ['distance costs', 'train scheduling', 'supply balancing']
        }

    def stage_7_megafactory(self):
        """
        STAGE 7: Planetary-Scale Production
        Goal: Graduate to endgame complexity
        """
        return {
            'name': 'Megafactory',
            'unlocked_buildings': ['all'],
            'unlocked_mechanics': ['blueprints', 'construction_bots'],
            'goal': 'Produce 6000+ science/min across 6 types',
            'complexity': 'EXTREME',
            'lesson': 'Megafactories require modular design and automated expansion',
            'endgame_systems': ['blueprint libraries', 'city blocks', 'train grids']
        }

Complexity Gating

class ComplexityGate:
    """
    Unlock new mechanics only after mastering current ones.
    Prevents overwhelming players.
    """
    def __init__(self):
        self.unlocks = {
            'basic_production': {
                'required_mastery': None,  # Always available
                'unlocks': ['miner', 'smelter', 'conveyor']
            },
            'bottleneck_identification': {
                'required_mastery': 'basic_production',
                'unlocks': ['status_indicators', 'throughput_display']
            },
            'parallel_scaling': {
                'required_mastery': 'bottleneck_identification',
                'unlocks': ['splitter', 'merger']
            },
            'ratio_optimization': {
                'required_mastery': 'parallel_scaling',
                'unlocks': ['ratio_calculator', 'efficiency_metrics']
            },
            'multi_stage_chains': {
                'required_mastery': 'ratio_optimization',
                'unlocks': ['assembler', 'complex_recipes']
            },
            'logistics': {
                'required_mastery': 'multi_stage_chains',
                'unlocks': ['trains', 'logistics_network']
            },
            'megafactory': {
                'required_mastery': 'logistics',
                'unlocks': ['blueprints', 'construction_bots', 'circuit_network']
            }
        }

    def check_unlock(self, player_mastery):
        """
        Gradually reveal complexity as player gains mastery.
        """
        available = []
        for system, requirements in self.unlocks.items():
            if requirements['required_mastery'] is None:
                available.extend(requirements['unlocks'])
            elif requirements['required_mastery'] in player_mastery:
                available.extend(requirements['unlocks'])
        return available

Mastery Progression Example: Satisfactory

class SatisfactoryProgression:
    """
    Example from Satisfactory: how complexity builds over time.
    """
    def __init__(self):
        self.tiers = [
            {
                'tier': 0,
                'name': 'Hub Upgrade 1',
                'available_buildings': ['miner_mk1', 'smelter', 'constructor'],
                'available_recipes': ['iron_ingot', 'iron_plate', 'iron_rod'],
                'complexity_rating': 1,
                'player_capability': 'Can build simple linear production chains'
            },
            {
                'tier': 2,
                'name': 'Hub Upgrade 3',
                'available_buildings': ['assembler', 'foundry'],
                'available_recipes': ['rotor', 'modular_frame', 'steel_beam'],
                'complexity_rating': 3,
                'player_capability': 'Can manage 2-input recipes and steel production'
            },
            {
                'tier': 4,
                'name': 'Hub Upgrade 5',
                'available_buildings': ['manufacturer', 'refinery'],
                'available_recipes': ['computer', 'heavy_modular_frame', 'plastic'],
                'complexity_rating': 6,
                'player_capability': 'Can manage 4+ input chains and fluids'
            },
            {
                'tier': 7,
                'name': 'Hub Upgrade 8',
                'available_buildings': ['particle_accelerator', 'quantum_encoder'],
                'available_recipes': ['nuclear_power', 'uranium_fuel_rod', 'turbo_motor'],
                'complexity_rating': 10,
                'player_capability': 'Can manage planet-scale logistics with nuclear power'
            }
        ]

    def get_appropriate_challenge(self, player_tier):
        """
        Match challenge complexity to player progression.
        """
        tier_data = self.tiers[player_tier]
        return {
            'available_tools': tier_data['available_buildings'],
            'recipes': tier_data['available_recipes'],
            'expected_factory_scale': 10 ** (tier_data['complexity_rating'] / 3)
        }

SECTION 6: Discovery Through Experimentation

The Discovery Principle

"Don't make players calculate optimal ratios. Let them discover through play."

In-Game Experimentation Tools

class ExperimentationTools:
    """
    Tools that help players discover optimal solutions through play,
    not spreadsheets.
    """

    class RatioCalculator:
        """
        In-game tool showing perfect ratios.
        Removes need for external calculators.
        """
        def show_recipe_requirements(self, target_recipe, target_throughput):
            """
            Show player what buildings they need for desired throughput.
            """
            recipe = RECIPES[target_recipe]

            # Calculate buildings needed for target throughput
            buildings_needed = {}

            # For each input resource
            for input_item, amount_needed in recipe.inputs.items():
                # Find recipe that produces this input
                producer_recipe = find_recipe_producing(input_item)
                producer_throughput = producer_recipe.output_per_minute

                # How many buildings to produce enough?
                required_count = math.ceil(
                    (amount_needed * target_throughput) / producer_throughput
                )
                buildings_needed[producer_recipe.building] = required_count

            # Display results
            display_panel = Panel("Ratio Calculator")
            display_panel.add_text(f"To produce {target_throughput} {target_recipe}/min:")
            for building, count in buildings_needed.items():
                display_panel.add_row(f"{count}x {building}")

            return display_panel

    class TestBench:
        """
        Sandbox area to test designs without resource cost.
        Encourages experimentation.
        """
        def __init__(self):
            self.test_mode = False
            self.test_factory = None

        def enter_test_mode(self):
            """
            Free building, instant placement, time controls.
            """
            self.test_mode = True
            self.test_factory = Factory(mode='TEST')

            # Test mode features
            self.test_factory.infinite_resources = True
            self.test_factory.free_buildings = True
            self.test_factory.time_controls = {
                'speed': 1.0,  # Can speed up time to see results faster
                'can_fast_forward': True,
                'can_rewind': True
            }

        def exit_test_mode(self, save_to_blueprint=False):
            """
            Exit test bench, optionally save working design.
            """
            if save_to_blueprint:
                self.save_as_blueprint(self.test_factory)
            self.test_mode = False

    class ThroughputAnalyzer:
        """
        Highlight where throughput drops in production chain.
        """
        def analyze_chain(self, start_building, end_building):
            """
            Trace production from start to end, showing throughput at each step.
            """
            chain = trace_production_chain(start_building, end_building)

            for i, node in enumerate(chain):
                throughput = node.measure_throughput()
                max_throughput = node.max_throughput
                utilization = throughput / max_throughput

                # Visualize
                draw_chain_node(node, utilization)

                # Show throughput number
                draw_text(f"{throughput:.1f}/min",
                         position=node.position + Vector2(0, -30))

                # Highlight bottleneck
                if utilization < 0.9 and i > 0:
                    # This node is slowest link
                    draw_bottleneck_highlight(node)
                    draw_tooltip(node.position,
                               f"BOTTLENECK: Only {throughput:.0f}/min (max {max_throughput:.0f}/min)")

Experimentation-Friendly Design

class ExperimentationFriendlyFactory:
    """
    Design choices that encourage experimentation.
    """
    def __init__(self):
        # LOW COST to experiment
        self.building_refund_percentage = 0.75  # Get 75% resources back when demolish
        self.instant_deconstruction = True  # No waiting to tear down

        # FAST iteration
        self.placement_speed = 'INSTANT'  # No construction time in early game
        self.blueprint_system = True  # Copy/paste working designs

        # SAFE experimentation
        self.test_mode_available = True  # Sandbox with no resource cost
        self.undo_system = True  # Can revert last 10 actions

        # VISIBLE results
        self.throughput_updates_per_second = 4  # See changes immediately
        self.before_after_comparison = True  # Can compare pre/post optimization

    def encourage_iteration(self):
        """
        Design systems that reward rebuilding and iteration.
        """
        features = {
            'refund_on_deconstruct': True,  # Not punishing to tear down and rebuild
            'blueprint_library': True,  # Save good designs for reuse
            'quick_paste': True,  # Rapid placement of saved blueprints
            'time_fast_forward': True,  # Speed up time to see results faster
            'A_B_testing': True  # Build two designs side-by-side to compare
        }
        return features

Discovery Moments: "Aha!" Design

class DiscoveryMoments:
    """
    Design for breakthrough moments where player discovers
    clever optimization that dramatically improves factory.
    """

    def example_discovery_1_splitter_balancing(self):
        """
        DISCOVERY: Using splitters to balance load across parallel buildings.

        Before (naive):
        Miner → Belt → [Building 1, Building 2, Building 3]
        Problem: Building 1 gets all items, others sit idle

        After (discovery):
        Miner → Belt → Splitter → [Building 1]
                         ↓
                      Splitter → [Building 2]
                         ↓
                     [Building 3]
        Result: Even distribution, 3x throughput!
        """
        pass

    def example_discovery_2_sideloading(self):
        """
        DISCOVERY: Sideloading to merge belts without splitters.

        Standard: Belt1 → Merger ← Belt2 (requires merger building)
        Discovery: Belt1 → ↓
                           Belt2 (items merge naturally)

        Benefit: No building required, saves space and cost
        """
        pass

    def example_discovery_3_priority_splitting(self):
        """
        DISCOVERY: Priority splitters to ensure critical production never starves.

        Problem: Power + Consumer both need coal, but power runs out first (blackout)

        Solution: Coal → Priority Splitter → Power (gets coal first)
                                           → Consumer (gets leftovers)

        Result: Power always stable, consumer only uses excess
        """
        pass

    def example_discovery_4_clock_cycles(self):
        """
        DISCOVERY: Using timing to create perfect ratios with different-speed buildings.

        Example from SpaceChem:
        - Reactor A takes 5 cycles to produce molecule
        - Reactor B takes 3 cycles to process it
        - Discovery: Build 3 of A and 5 of B for perfect ratio (15 cycles each)
        """
        pass

    def create_discoverable_mechanics(self):
        """
        Design mechanics that have hidden depth.
        Players discover advanced uses through experimentation.
        """
        return {
            'basic_use': 'Obvious, taught in tutorial',
            'intermediate_use': 'Hinted at, player discovers',
            'advanced_use': 'Emergent, community shares',
            'expert_use': 'Unintended by designer, players innovate'
        }

# Example: Conveyor Belt Mechanics (Factorio)
conveyor_belt_depth = {
    'basic_use': 'Transport items from A to B',
    'intermediate_use': 'Can be placed in parallel for higher throughput',
    'advanced_use': 'Sideloading merges belts without splitter buildings',
    'expert_use': 'Lane balancing using underground belt tricks'
}

SECTION 7: Community Competition & Sharing

The Sharing Principle

"Optimization thrives when players can compare and compete. Standardized challenges enable community."

Challenge System for Competition

class CompetitiveChallenge:
    """
    Standardized scenario that players compete on.
    """
    def __init__(self, name, description):
        self.name = name
        self.description = description
        self.leaderboards = {
            'speed': Leaderboard('Fastest Throughput'),
            'cost': Leaderboard('Most Cost-Efficient'),
            'compact': Leaderboard('Smallest Footprint'),
            'power': Leaderboard('Lowest Power Usage'),
            'elegant': Leaderboard('Community Votes')
        }

    def define_constraints(self):
        """
        Fixed starting conditions ensure fair comparison.
        """
        return {
            'starting_resources': {'iron': 1000, 'copper': 500, 'coal': 200},
            'available_buildings': ['miner', 'smelter', 'assembler', 'conveyor'],
            'map_size': (20, 20),  # Limited space
            'power_capacity': 50,  # Limited power
            'objective': 'Produce 100 circuits/min',
            'time_limit': None  # No time pressure (optimize at leisure)
        }

    def submit_solution(self, player, factory):
        """
        Player submits their solution for ranking.
        """
        # Validate solution meets constraints
        if not self.validate_solution(factory):
            return {'error': 'Solution violates constraints'}

        # Measure performance across all dimensions
        scores = {
            'throughput': factory.measure_throughput(),
            'cost': factory.calculate_total_cost(),
            'footprint': factory.calculate_footprint(),
            'power': factory.total_power_consumption()
        }

        # Submit to leaderboards
        for dimension, leaderboard in self.leaderboards.items():
            leaderboard.submit(player, scores[dimension], factory.screenshot())

        # Enable sharing
        share_link = self.generate_share_link(player, factory)
        return {'success': True, 'share_link': share_link, 'scores': scores}

    def generate_share_link(self, player, factory):
        """
        Create shareable link/code for solution.
        Other players can view or copy the design.
        """
        blueprint = factory.export_to_blueprint()
        encoded = encode_blueprint(blueprint)
        url = f"https://game.com/challenges/{self.name}/{player.id}/{encoded}"
        return url

Blueprint Sharing System

class BlueprintSystem:
    """
    Let players save and share factory designs.
    Like sharing cookie recipes but for optimization.
    """
    def __init__(self):
        self.library = {}

    def create_blueprint(self, factory, name, description):
        """
        Save current factory design as reusable blueprint.
        """
        blueprint = {
            'name': name,
            'description': description,
            'author': current_player(),
            'created_at': now(),
            'buildings': [b.serialize() for b in factory.buildings],
            'conveyors': [c.serialize() for c in factory.conveyors],
            'performance': {
                'throughput': factory.measure_throughput(),
                'cost': factory.calculate_cost(),
                'footprint': factory.calculate_footprint()
            },
            'tags': self.auto_generate_tags(factory)
        }

        # Generate shareable code
        blueprint['share_code'] = self.encode_blueprint(blueprint)

        return blueprint

    def encode_blueprint(self, blueprint):
        """
        Convert blueprint to compact shareable string.
        Like Factorio's blueprint strings.
        """
        # Serialize to JSON
        json_data = json.dumps(blueprint)
        # Compress
        compressed = zlib.compress(json_data.encode())
        # Base64 encode
        encoded = base64.b64encode(compressed).decode()
        return encoded

    def import_blueprint(self, share_code):
        """
        Import someone else's blueprint from share code.
        """
        # Decode
        compressed = base64.b64decode(share_code)
        # Decompress
        json_data = zlib.decompress(compressed).decode()
        # Parse
        blueprint = json.loads(json_data)
        return blueprint

    def paste_blueprint(self, blueprint, position):
        """
        Place blueprint in world at specified position.
        """
        for building_data in blueprint['buildings']:
            building = Building.deserialize(building_data)
            building.position += position  # Offset to paste position
            factory.add_building(building)

        for conveyor_data in blueprint['conveyors']:
            conveyor = Conveyor.deserialize(conveyor_data)
            conveyor.offset_by(position)
            factory.add_conveyor(conveyor)

Community Leaderboards

class Leaderboard:
    """
    Competitive rankings for optimization challenges.
    """
    def __init__(self, name, metric, order='DESC'):
        self.name = name
        self.metric = metric  # 'throughput', 'cost', 'footprint', etc.
        self.order = order  # DESC = higher is better, ASC = lower is better
        self.entries = []

    def submit(self, player, score, screenshot):
        """
        Add entry to leaderboard.
        """
        entry = {
            'player': player,
            'score': score,
            'screenshot': screenshot,
            'timestamp': now(),
            'verified': False  # Anti-cheat verification pending
        }

        self.entries.append(entry)
        self.sort_entries()

        # Notify player of rank
        rank = self.get_player_rank(player)
        return rank

    def sort_entries(self):
        """Sort by score (ascending or descending)"""
        reverse = (self.order == 'DESC')
        self.entries.sort(key=lambda e: e['score'], reverse=reverse)

    def get_top_entries(self, count=100):
        """Get top N entries"""
        return self.entries[:count]

    def render_leaderboard(self):
        """
        Display leaderboard with ranks, scores, and screenshots.
        """
        for i, entry in enumerate(self.get_top_entries(10)):
            rank = i + 1

            # Medal for top 3
            if rank == 1:
                medal = "🥇"
            elif rank == 2:
                medal = "🥈"
            elif rank == 3:
                medal = "🥉"
            else:
                medal = f"#{rank}"

            # Display entry
            draw_leaderboard_entry(
                rank=medal,
                player=entry['player'].name,
                score=f"{entry['score']:.1f}",
                screenshot=entry['screenshot'],
                clickable=True  # Click to view full design
            )

Example: Opus Magnum Histograms

class OpusMagnumStyleHistogram:
    """
    Brilliant leaderboard design from Opus Magnum:
    Shows distribution of all solutions, player sees where they rank.
    """
    def __init__(self, challenge):
        self.challenge = challenge
        self.all_solutions = []  # Every submitted solution

    def generate_pareto_frontier(self):
        """
        Pareto frontier: solutions that are optimal in at least one dimension.

        Example:
        Solution A: Cost 50, Cycles 100, Size 10 (optimal cost)
        Solution B: Cost 80, Cycles 60, Size 15 (optimal cycles)
        Solution C: Cost 100, Cycles 120, Size 8 (optimal size)
        Solution D: Cost 60, Cycles 110, Size 12 (NOT on frontier, A is better in all dimensions)
        """
        frontier = []

        for solution in self.all_solutions:
            is_optimal = False

            # Check if solution is best in ANY dimension
            for dimension in ['cost', 'cycles', 'size']:
                if solution[dimension] == min(s[dimension] for s in self.all_solutions):
                    is_optimal = True
                    break

            if is_optimal:
                frontier.append(solution)

        return frontier

    def render_histogram(self, dimension='cost'):
        """
        Show histogram of all solutions for given dimension.
        Player's solution highlighted.
        """
        # Collect all scores for this dimension
        scores = [s[dimension] for s in self.all_solutions]

        # Create histogram buckets
        min_score = min(scores)
        max_score = max(scores)
        bucket_count = 20
        bucket_size = (max_score - min_score) / bucket_count

        buckets = [0] * bucket_count
        for score in scores:
            bucket_index = int((score - min_score) / bucket_size)
            bucket_index = min(bucket_index, bucket_count - 1)  # Edge case
            buckets[bucket_index] += 1

        # Draw histogram
        for i, count in enumerate(buckets):
            bucket_min = min_score + i * bucket_size
            bucket_max = bucket_min + bucket_size

            # Draw bar
            bar_height = count / max(buckets) * 100  # Normalize to 100 pixels
            draw_bar(x=i * 10, height=bar_height, color=BLUE)

            # Highlight player's bucket
            if player_solution[dimension] >= bucket_min and player_solution[dimension] < bucket_max:
                draw_bar(x=i * 10, height=bar_height, color=GOLD, highlight=True)

        # Show percentile
        percentile = (sum(1 for s in scores if s > player_solution[dimension]) / len(scores)) * 100
        draw_text(f"You're in the top {percentile:.0f}% for {dimension}!")

SECTION 8: Real-World Implementation Examples

Example 1: Factorio's Production Lines

class FactorioProductionLine:
    """
    Factorio's genius: perfect ratios create satisfying optimization.
    """
    def __init__(self):
        # Real Factorio recipes
        self.recipes = {
            'iron_plate': {
                'input': ('iron_ore', 1),
                'output': ('iron_plate', 1),
                'time': 3.2,  # seconds in stone furnace
                'building': 'stone_furnace'
            },
            'copper_cable': {
                'input': ('copper_plate', 1),
                'output': ('copper_cable', 2),
                'time': 0.5,
                'building': 'assembling_machine'
            },
            'electronic_circuit': {
                'input': [('iron_plate', 1), ('copper_cable', 3)],
                'output': ('electronic_circuit', 1),
                'time': 0.5,
                'building': 'assembling_machine'
            }
        }

    def calculate_factorio_ratios(self):
        """
        Perfect ratios for circuit production:

        1 Assembler (circuits) needs:
        - 1 iron plate per 0.5s = 120/min
        - 3 copper cable per 0.5s = 360/min

        1 Assembler (copper cable) produces:
        - 2 cable per 0.5s = 240/min

        Therefore perfect ratio:
        - 1 Copper Cable Assembler : 0.67 Circuit Assemblers
        - OR: 3 Copper Cable : 2 Circuits
        """

        circuit_assembler_cable_consumption = 360  # per minute
        cable_assembler_production = 240  # per minute

        ratio = circuit_assembler_cable_consumption / cable_assembler_production
        print(f"Need {ratio:.2f} cable assemblers per circuit assembler")
        # Output: "Need 1.50 cable assemblers per circuit assembler"
        # In practice: 3 cable assemblers for every 2 circuit assemblers

Example 2: Opus Magnum's Optimization Puzzle

class OpusMagnumAlchemyPuzzle:
    """
    Opus Magnum: Optimization puzzle with 3 scoring dimensions.
    """
    def __init__(self, puzzle_name):
        self.puzzle_name = puzzle_name
        self.scoring_dimensions = ['cost', 'cycles', 'area']

    def example_puzzle_health_potion(self):
        """
        Puzzle: Create health potion from base elements.

        Constraints:
        - Input: 2 Fire + 1 Water + 1 Salt
        - Output: 1 Health Potion
        - Mechanics: Grabber arms, rotation, bonds

        Three approaches:
        """

        # Approach 1: SPEED OPTIMIZATION
        speed_solution = {
            'cost': 350,     # Expensive (many arms)
            'cycles': 45,    # FAST (parallel processing)
            'area': 25,      # Large (spread out for speed)
            'strategy': 'Multiple grabber arms working in parallel'
        }

        # Approach 2: COST OPTIMIZATION
        cost_solution = {
            'cost': 90,      # CHEAP (minimal arms)
            'cycles': 180,   # Slow (serial processing)
            'area': 18,      # Medium
            'strategy': 'Single grabber arm doing everything (slow but cheap)'
        }

        # Approach 3: AREA OPTIMIZATION
        area_solution = {
            'cost': 220,     # Medium
            'cycles': 95,    # Medium
            'area': 9,       # COMPACT (everything overlapped)
            'strategy': 'Clever overlapping paths to minimize footprint'
        }

        return [speed_solution, cost_solution, area_solution]

    def score_solution(self, solution):
        """
        Each dimension has its own leaderboard.
        Players compete for records in each dimension.
        """
        leaderboards = {
            'cost': {'record': 85, 'player_score': solution['cost']},
            'cycles': {'record': 42, 'player_score': solution['cycles']},
            'area': {'record': 8, 'player_score': solution['area']}
        }

        for dimension, data in leaderboards.items():
            if data['player_score'] < data['record']:
                celebrate_new_record(dimension)

Example 3: Satisfactory's 3D Factory Optimization

class Satisfactory3DFactory:
    """
    Satisfactory adds vertical dimension to factory optimization.
    """
    def __init__(self):
        self.grid = Grid3D(width=100, depth=100, height=50)

    def vertical_optimization_strategies(self):
        """
        3D space enables unique optimization strategies.
        """
        strategies = {
            'spaghetti': {
                'description': 'Conveyors everywhere, no organization',
                'pros': ['Fast to build', 'Works'],
                'cons': ['Hard to debug', 'Ugly', 'Hard to expand'],
                'visual': 'Messy but functional'
            },
            'city_blocks': {
                'description': 'Grid of modular production cells',
                'pros': ['Organized', 'Expandable', 'Debuggable'],
                'cons': ['Slower to build', 'Uses more space'],
                'visual': 'Clean grid pattern'
            },
            'vertical_layers': {
                'description': 'Each production stage on different floor',
                'pros': ['Clear flow', 'Easy to see throughput', 'Compact horizontally'],
                'cons': ['Tall structures', 'Lots of vertical conveyors'],
                'visual': 'Skyscraper factory'
            },
            'mall_layout': {
                'description': 'Central bus of resources, production branches off',
                'pros': ['Easy to add new production', 'Shared resources'],
                'cons': ['Main bus can bottleneck', 'Gets wide'],
                'visual': 'Highway with offramps'
            }
        }
        return strategies

    def calculate_3d_optimization(self, factory_3d):
        """
        3D adds complexity: vertical conveyors, lifts, multi-floor layouts.
        """
        metrics = {
            'horizontal_footprint': factory_3d.calculate_2d_area(),
            'vertical_footprint': factory_3d.max_height,
            'total_conveyor_length': factory_3d.total_belt_length(),
            'vertical_conveyor_count': factory_3d.count_vertical_lifts(),
            'throughput': factory_3d.measure_throughput()
        }

        # Optimization: Minimize conveyor length (faster transport)
        # vs Minimize footprint (compact base)
        # vs Minimize height (easier to navigate)

        return metrics

Example 4: SpaceChem's Constraint Optimization

class SpaceChemReactor:
    """
    SpaceChem: Optimization under strict constraints.
    """
    def __init__(self):
        self.grid_size = (10, 8)  # Fixed size reactor
        self.max_symbols = None  # Unlimited instructions

    def example_puzzle_methane_synthesis(self):
        """
        Puzzle: Synthesize methane (CH4) from C and H atoms.

        Constraints:
        - 10x8 grid (fixed size)
        - 2 waldos (robot arms) per reactor
        - Instructions: grab, drop, bond, rotate, sync

        Optimization dimensions:
        - Cycles: How fast does it produce one molecule?
        - Symbols: How many instructions used? (code golf)
        - Reactors: How many reactors needed? (less is better)
        """

        solution_simple = {
            'cycles': 95,
            'symbols': 34,
            'reactors': 1,
            'description': 'Straightforward solution, no tricks'
        }

        solution_optimized_cycles = {
            'cycles': 52,
            'symbols': 48,
            'reactors': 1,
            'description': 'Waldos work in parallel, clever synchronization'
        }

        solution_optimized_symbols = {
            'cycles': 120,
            'symbols': 18,
            'description': 'Minimal instructions, reuse paths, slower but elegant'
        }

        return [solution_simple, solution_optimized_cycles, solution_optimized_symbols]

    def scoring_system(self):
        """
        SpaceChem's brilliant scoring:
        - Histograms show distribution of all solutions
        - Player sees percentile ranking
        - Pareto frontier shows optimal solutions
        - Community competitions for lowest cycles/symbols
        """
        return {
            'primary_metric': 'Puzzle completed (yes/no)',
            'secondary_metrics': ['Cycles', 'Symbols', 'Reactors'],
            'presentation': 'Histogram + Pareto frontier',
            'social': 'View friends\' solutions, compete for records'
        }

Example 5: Dyson Sphere Program's Planetary Logistics

class DysonSphereProgramLogistics:
    """
    DSP: Planet-scale and interstellar logistics optimization.
    """
    def __init__(self):
        self.planets = []
        self.interstellar_logistics = []

    def planetary_production(self):
        """
        Each planet specializes in different resources.
        """
        planets = {
            'starter_planet': {
                'resources': ['iron', 'copper', 'coal'],
                'production': 'Basic materials',
                'exports': 'Iron plates, copper wire',
                'imports': 'Advanced components'
            },
            'oil_planet': {
                'resources': ['oil'],
                'production': 'Plastic, organic crystals',
                'exports': 'Plastic, graphene',
                'imports': 'None (self-sufficient)'
            },
            'silicon_planet': {
                'resources': ['silicon'],
                'production': 'Processors, quantum chips',
                'exports': 'High-tech components',
                'imports': 'Copper wire, plastic'
            }
        }
        return planets

    def interstellar_optimization(self):
        """
        Optimize logistics across star systems.

        Challenges:
        - Travel time (minutes between planets)
        - Vessel capacity (how much to carry)
        - Fuel costs (warp fuel consumption)
        - Throughput (items per minute across vast distances)
        """

        optimization_strategies = {
            'local_production': {
                'description': 'Produce everything locally on each planet',
                'pros': ['No logistics complexity', 'Self-sufficient'],
                'cons': ['Inefficient', 'Duplicate infrastructure']
            },
            'specialized_planets': {
                'description': 'Each planet specializes, ships between them',
                'pros': ['Efficient resource use', 'Interesting optimization'],
                'cons': ['Complex logistics', 'Bottlenecks from shipping']
            },
            'hub_and_spoke': {
                'description': 'One hub planet, spokes gather resources',
                'pros': ['Centralized production', 'Easy to optimize'],
                'cons': ['Hub can bottleneck', 'Long shipping routes']
            }
        }

        return optimization_strategies

SECTION 9: Common Pitfalls & Solutions

Pitfall 1: Hidden Math (Spreadsheet Required)

Problem: Players need Excel to calculate optimal ratios.

# BAD: Requires external calculation
class HiddenMathFactory:
    """
    Player must manually calculate:
    - Building A produces 7.2 items per second
    - Building B consumes 3.1 items per second
    - Ratio = 7.2 / 3.1 = 2.32...
    - Need 23 of A and 10 of B for perfect ratio

    This is HOMEWORK, not gameplay.
    """
    pass

# GOOD: In-game tools show ratios
class TransparentMathFactory:
    """
    Hover over building → tooltip shows:
    "Produces 7.2/sec iron plates"
    "Perfect ratio: 23 miners → 10 smelters"

    Player learns through UI, not spreadsheets.
    """
    def show_ratio_tooltip(self, building):
        recipe = building.recipe

        # Calculate optimal ratio to other buildings
        ratios = calculate_optimal_ratios(recipe)

        tooltip = f"{building.name}\n"
        tooltip += f"Produces: {recipe.output_rate:.1f}/sec\n"
        tooltip += f"Perfect ratio:\n"

        for other_building, ratio in ratios.items():
            tooltip += f"  {ratio:.1f}x {other_building}\n"

        return tooltip

Solution: In-game ratio calculator, tooltips showing perfect ratios, visual indicators when ratio is off.


Pitfall 2: One Optimal Solution

Problem: Every player builds identical factory because only one design works.

# BAD: Single optimal solution
class SingleSolutionPuzzle:
    """
    Only one way to achieve target throughput.
    Player looks up solution online, copies it.
    No creativity, no optimization gameplay.
    """
    def __init__(self):
        self.target = 100  # items/min
        self.only_valid_design = [
            Building('miner', position=(0, 0)),
            Building('miner', position=(1, 0)),
            Building('smelter', position=(2, 0)),
            # ... exact layout required ...
        ]

# GOOD: Multiple valid approaches
class MultiSolutionPuzzle:
    """
    Many ways to achieve target, each with tradeoffs.
    """
    def __init__(self):
        self.target = 100
        self.constraints = {
            'max_cost': 1000,  # But not too strict
            'max_footprint': 50,
            'max_power': 30
        }
        # Players can optimize for speed, cost, OR space
        # Multiple valid solutions exist

Solution: Design challenges with multiple optimization dimensions. Tradeoffs ensure no single best solution.


Pitfall 3: No Visible Feedback

Problem: Can't see why factory is slow or what to improve.

# BAD: Invisible problems
class InvisibleBottlenecks:
    """
    Factory is slow but player has no idea why.
    No indicators, no metrics, just frustration.
    """
    def update(self):
        # Factory runs but nothing tells player about problems
        for building in self.buildings:
            building.update()  # Silently starved or blocked

# GOOD: Clear visual feedback
class VisibleBottlenecks:
    """
    Player instantly sees problems:
    - Red buildings are input-starved
    - Yellow buildings are output-blocked
    - Green buildings are running optimally
    - Numbers show exact throughput
    """
    def render(self):
        for building in self.buildings:
            # Status color
            color = {
                'STARVED': RED,
                'BLOCKED': YELLOW,
                'OPTIMAL': GREEN
            }[building.status]

            # Draw with status indicator
            building.render_with_status(color)

            # Show throughput
            draw_text(f"{building.throughput:.0f}/min", building.position)

Solution: Rich visual feedback, status indicators, throughput numbers, bottleneck highlighting.


Pitfall 4: Overwhelming Complexity at Start

Problem: Tutorial dumps 20 building types and complex ratios immediately.

# BAD: Everything at once
class OverwhelmingTutorial:
    """
    Tutorial: "Here are 20 building types, 15 resource types,
    power system, fluids, trains, and circuits. Good luck!"

    Result: Player quits, overwhelmed.
    """
    def tutorial(self):
        unlock_buildings(['miner', 'smelter', 'assembler', 'chemical_plant',
                         'refinery', 'rocket_silo', ...])  # TOO MUCH

# GOOD: Progressive revelation
class ProgressiveTutorial:
    """
    Stage 1: Just miner + smelter
    Stage 2: Add assembler
    Stage 3: Add parallel production
    Stage 4: Add logistics
    ...

    Each stage builds on previous mastery.
    """
    def tutorial_stage_1(self):
        unlock_buildings(['miner', 'smelter'])
        goal = "Produce 10 iron plates"
        # Master this first, then move on

Solution: Progressive complexity gating. Unlock new mechanics only after mastering current ones.


Pitfall 5: No Stakes (Optimization Doesn't Matter)

Problem: Players can ignore optimization and still progress fine.

# BAD: Optimization is optional busywork
class NoStakesGame:
    """
    Inefficient factory works just as well as optimized one.
    No motivation to improve.
    """
    def progress_gate(self, factory):
        # Gate only checks if factory EXISTS, not if it's good
        if factory.has_any_production():
            unlock_next_level()  # Optimization didn't matter

# GOOD: Optimization has intrinsic rewards
class IntrinsicRewardsGame:
    """
    Optimization is NOT required, but it's satisfying:
    - Visual satisfaction (smooth flow)
    - Competitive leaderboards
    - Personal challenge (beat your own record)
    - Efficiency achievements
    """
    def provide_intrinsic_motivation(self):
        return {
            'leaderboards': 'Compare with friends',
            'achievements': 'Personal mastery goals',
            'satisfaction': 'Watching efficient factory run',
            'creativity': 'Express personal style',
            'community': 'Share clever designs'
        }
        # NOT: "You must optimize to progress"
        # YES: "Optimizing feels good"

Solution: Make optimization intrinsically rewarding (satisfying visuals, community competition, personal achievement), not extrinsically required (gates blocking progress).


SECTION 10: Testing & Validation Checklist

Pre-Launch Checklist

class OptimizationGameplayChecklist:
    """
    Validate that optimization is actually fun.
    """
    def __init__(self):
        self.checks = []

    def visibility_checks(self):
        """Can players SEE performance?"""
        return [
            ("Throughput displayed in real-time", self.check_throughput_display()),
            ("Bottlenecks are visually highlighted", self.check_bottleneck_visualization()),
            ("Efficiency percentage shown", self.check_efficiency_metrics()),
            ("Status indicators on all buildings", self.check_status_indicators()),
            ("Dashboard with detailed analytics", self.check_dashboard_exists())
        ]

    def feedback_loop_checks(self):
        """Is iteration fast and satisfying?"""
        return [
            ("Changes reflect in < 1 second", self.check_update_speed()),
            ("Before/after comparison available", self.check_comparison_tool()),
            ("Milestones celebrate improvements", self.check_celebration_system()),
            ("Audio feedback reflects throughput", self.check_audio_scaling()),
            ("Visual flow animations", self.check_flow_visualization())
        ]

    def tradeoff_checks(self):
        """Are there multiple valid solutions?"""
        return [
            ("Speed vs Cost tradeoffs exist", self.check_tradeoffs('speed', 'cost')),
            ("Compact vs Sprawling both viable", self.check_tradeoffs('footprint', 'flexibility')),
            ("High-power vs Low-power options", self.check_tradeoffs('power', 'throughput')),
            ("At least 3 valid approaches per challenge", self.check_solution_diversity()),
            ("No single 'best' solution", self.check_pareto_frontier())
        ]

    def discovery_checks(self):
        """Can players discover through play?"""
        return [
            ("Ratio calculator in-game", self.check_ratio_tools()),
            ("Test bench for experimentation", self.check_sandbox_mode()),
            ("Refund on deconstruction", self.check_refund_system()),
            ("Blueprint save/load", self.check_blueprint_system()),
            ("Tutorial teaches discovery, not recipes", self.check_tutorial_style())
        ]

    def progression_checks(self):
        """Does complexity build gradually?"""
        return [
            ("First puzzle is trivial (< 5 min)", self.check_first_puzzle_simplicity()),
            ("Mechanics unlocked progressively", self.check_unlock_pacing()),
            ("Each stage requires mastery of previous", self.check_mastery_gates()),
            ("Endgame complexity >> starting complexity", self.check_depth_curve()),
            ("No overwhelming info dumps", self.check_tutorial_pacing())
        ]

    def community_checks(self):
        """Can players share and compete?"""
        return [
            ("Challenge system with leaderboards", self.check_leaderboard_exists()),
            ("Blueprint sharing implemented", self.check_sharing_system()),
            ("Multiple leaderboard dimensions", self.check_leaderboard_dimensions()),
            ("Screenshot/video export", self.check_export_tools()),
            ("Community can upvote designs", self.check_voting_system())
        ]

    def satisfaction_checks(self):
        """Does optimization FEEL good?"""
        return [
            ("Numbers going up is visible", self.check_visible_progress()),
            ("Smooth animations for production", self.check_animation_quality()),
            ("Satisfying audio for efficiency", self.check_audio_juice()),
            ("Celebration for milestones", self.check_celebration_moments()),
            ("Pride in showing off factory", self.check_shareability())
        ]

    def run_all_checks(self):
        """
        Run complete validation suite.
        """
        all_checks = (
            self.visibility_checks() +
            self.feedback_loop_checks() +
            self.tradeoff_checks() +
            self.discovery_checks() +
            self.progression_checks() +
            self.community_checks() +
            self.satisfaction_checks()
        )

        passed = sum(1 for _, check in all_checks if check)
        total = len(all_checks)

        print(f"Optimization Gameplay Validation: {passed}/{total} checks passed")

        if passed < total * 0.8:
            print("WARNING: Optimization may not be engaging enough")

        return passed / total

Playtesting Metrics

class OptimizationPlaytestMetrics:
    """
    Measure whether players actually enjoy optimizing.
    """
    def __init__(self):
        self.metrics = {}

    def measure_engagement(self, playtest_session):
        """
        Track behavioral indicators of engagement.
        """
        return {
            'time_spent_optimizing': playtest_session.time_in_optimization_mode,
            'factories_rebuilt': playtest_session.count_rebuilds,
            'aha_moments': playtest_session.count_verbal_eureka(),
            'voluntary_optimization': playtest_session.optimized_without_prompt,
            'blueprint_usage': playtest_session.blueprints_created,
            'repeated_play': playtest_session.returned_to_same_challenge
        }

    def measure_satisfaction(self, playtest_session):
        """
        Qualitative measures of satisfaction.
        """
        return {
            'verbal_positive': playtest_session.count_positive_exclamations(),
            'leaned_forward': playtest_session.body_language_engagement,
            'showed_friend': playtest_session.unprompted_sharing,
            'requested_more': playtest_session.asked_for_next_challenge,
            'post_survey_rating': playtest_session.survey_score()
        }

    def red_flags(self, playtest_session):
        """
        Warning signs that optimization isn't fun.
        """
        warnings = []

        if playtest_session.opened_external_calculator:
            warnings.append("Player needed external tool (provide in-game calculator)")

        if playtest_session.time_idle > playtest_session.time_building:
            warnings.append("More waiting than doing (speed up feedback loop)")

        if playtest_session.asked_for_optimal_solution:
            warnings.append("Player wants answer, not discovery (improve discovery tools)")

        if playtest_session.verbal_frustration > 3:
            warnings.append("High frustration (unclear feedback or too difficult)")

        if playtest_session.quit_before_completion:
            warnings.append("Abandoned puzzle (check difficulty curve)")

        return warnings

SECTION 11: Decision Framework

When to Use Optimization-as-Play

class DecisionFramework:
    """
    Help designers decide if optimization-as-play fits their game.
    """

    def should_use_optimization_as_play(self, game_design):
        """
        Decision tree for choosing this design pattern.
        """

        # REQUIRED prerequisites
        if not game_design.has_systemic_production():
            return False, "No production systems to optimize"

        if not game_design.has_measurable_metrics():
            return False, "Can't optimize what you can't measure"

        # STRONG indicators this will work
        positive_signals = [
            game_design.players_enjoy_efficiency,
            game_design.multiple_solutions_possible,
            game_design.bottlenecks_are_natural,
            game_design.mastery_curve_exists,
            game_design.community_competition_viable
        ]

        # WARNING signs this might not work
        negative_signals = [
            game_design.action_focused,  # Real-time action != optimization
            game_design.narrative_heavy,  # Story pacing != optimization pacing
            game_design.only_one_solution,  # No room for creativity
            game_design.instant_gratification_required,  # Optimization takes time
            game_design.metrics_feel_artificial  # Must be natural to game
        ]

        score = sum(positive_signals) - sum(negative_signals)

        if score >= 3:
            return True, "Strong fit for optimization-as-play"
        elif score >= 1:
            return True, "Could work with careful design"
        else:
            return False, "Optimization might feel tacked-on"

    def alternatives_if_not_suitable(self):
        """
        If optimization-as-play isn't right, what else?
        """
        return {
            'action_games': 'Use execution-based challenges (combat, platforming)',
            'narrative_games': 'Use story choices and character progression',
            'puzzle_games': 'Use fixed-solution puzzles (no optimization axis)',
            'exploration_games': 'Use discovery and collection as rewards'
        }

Hybrid Approaches

class HybridOptimization:
    """
    Optimization-as-play can be PART of game, not the whole game.
    """

    def example_mindustry(self):
        """
        Mindustry: Tower defense + factory optimization hybrid.
        """
        return {
            'primary_gameplay': 'Tower defense (action)',
            'secondary_gameplay': 'Factory optimization (strategy)',
            'integration': 'Better factory → better towers → easier defense',
            'time_split': '60% action, 40% optimization',
            'works_because': 'Optimization happens between waves, not during'
        }

    def example_oxygen_not_included(self):
        """
        Oxygen Not Included: Survival + resource optimization.
        """
        return {
            'primary_gameplay': 'Colony survival (crisis management)',
            'secondary_gameplay': 'Resource optimization (efficiency)',
            'integration': 'Efficient systems free up time to explore',
            'time_split': '50% crisis response, 50% optimization',
            'works_because': 'Optimization reduces future crises'
        }

    def example_cracktorio_drug_production(self):
        """
        Hypothetical: Factorio-like illegal drug production sim.
        """
        return {
            'primary_gameplay': 'Factory optimization (production chains)',
            'secondary_gameplay': 'Risk management (police, competitors)',
            'integration': 'Efficient production → more profit → better defenses',
            'twist': 'Optimization under pressure (police raids interrupt production)',
            'works_because': 'Optimization is central but not the only challenge'
        }

SECTION 12: Conclusion & Summary

Core Principles Recap

class OptimizationAsPlayPrinciples:
    """
    The 10 commandments of optimization-as-play design.
    """

    def __init__(self):
        self.principles = {
            1: "Make metrics VISIBLE (throughput, efficiency, bottlenecks)",
            2: "Identify bottlenecks as CORE MECHANIC (whack-a-mole gameplay)",
            3: "Design TRADEOFFS (speed vs cost vs space vs power)",
            4: "Make optimization SATISFYING (juice, celebration, feedback)",
            5: "Progressive COMPLEXITY (simple → complex as player learns)",
            6: "Enable DISCOVERY (experimentation, not calculation)",
            7: "Support COMMUNITY (sharing, competition, leaderboards)",
            8: "Provide TOOLS (ratio calculator, test bench, blueprints)",
            9: "Ensure MULTIPLE SOLUTIONS (no single 'best' answer)",
            10: "Make it OPTIONAL but IRRESISTIBLE (intrinsic motivation)"
        }

    def the_golden_rule(self):
        """
        If you remember only one thing:
        """
        return "Optimization must be THE GAME, not a chore you do to play the game."

The Optimization Gameplay Loop (Final Form)

OBSERVE
  ↓
  Factory running, metrics displayed
  ↓
IDENTIFY
  ↓
  Bottleneck highlighted (RED building)
  ↓
HYPOTHESIZE
  ↓
  "If I add another smelter, throughput should increase"
  ↓
EXPERIMENT
  ↓
  Build smelter, place it (instant feedback)
  ↓
MEASURE
  ↓
  Throughput increased! (satisfying animation, numbers go up)
  ↓
DISCOVER
  ↓
  "Wait, now the CONVEYOR is the bottleneck!" (cascade)
  ↓
ITERATE
  ↓
  (loop continues, always finding next optimization)

Success Criteria

Your optimization-as-play implementation succeeds when:

  1. Players spend hours optimizing for fun, not because they're forced
  2. Multiple solutions exist for every challenge (community discovers new approaches)
  3. Bottleneck discovery is engaging (detective work, not frustration)
  4. Metrics are clear (no external tools needed)
  5. Improvements feel satisfying (juice, celebration, visible progress)
  6. Complexity builds gradually (tutorial → mastery curve)
  7. Community thrives (sharing blueprints, competing on leaderboards)
  8. Discovery happens (players find clever solutions you didn't anticipate)
  9. Tradeoffs are meaningful (speed vs cost vs space, all valid)
  10. Players show off factories (pride in their creations)

Final Code Example: Complete System

class CompleteOptimizationGame:
    """
    Putting it all together: a complete optimization-as-play system.
    """
    def __init__(self):
        # Core systems
        self.factory = Factory()
        self.metrics = PerformanceMetrics()
        self.bottleneck_detector = BottleneckDetector(self.factory)
        self.visualizer = BottleneckVisualizer(self.bottleneck_detector)

        # Player tools
        self.ratio_calculator = RatioCalculator()
        self.test_bench = TestBench()
        self.blueprint_system = BlueprintSystem()

        # Progression
        self.tutorial = TutorialProgression()
        self.challenges = ChallengeSystem()
        self.milestones = MilestoneSystem()

        # Community
        self.leaderboards = LeaderboardSystem()
        self.sharing = SharingSystem()

        # Feedback
        self.audio = ProductionAudio(self.factory)
        self.celebrations = CelebrationSystem()

    def update(self, dt):
        """Main game loop"""
        # Update production
        self.factory.update(dt)

        # Update metrics (real-time feedback)
        self.metrics.items_per_minute = self.factory.measure_throughput()
        self.metrics.efficiency_percent = self.factory.calculate_efficiency() * 100

        # Detect bottlenecks (core mechanic)
        bottlenecks = self.bottleneck_detector.analyze()
        if bottlenecks:
            self.metrics.bottleneck_type = bottlenecks[0]['type']
            self.metrics.bottleneck_location = bottlenecks[0]['location']

        # Update audio (satisfaction)
        self.audio.update(dt)

        # Check milestones (celebration)
        self.milestones.check_milestones(self.metrics.items_per_minute)

    def render(self):
        """Visual feedback"""
        # Render factory with status indicators
        self.factory.render()

        # Highlight bottlenecks
        self.visualizer.render()

        # Display metrics HUD
        MetricsDisplay().render(self.metrics)

    def player_opens_ratio_calculator(self, recipe):
        """In-game tool replaces spreadsheets"""
        return self.ratio_calculator.show_recipe_requirements(recipe, target_throughput=100)

    def player_enters_test_mode(self):
        """Experimentation without cost"""
        self.test_bench.enter_test_mode()

    def player_submits_challenge_solution(self, challenge_id):
        """Community competition"""
        challenge = self.challenges.get_challenge(challenge_id)
        result = challenge.submit_solution(current_player(), self.factory)
        return result  # Contains rank, share link, scores

    def player_shares_blueprint(self, name, description):
        """Community sharing"""
        blueprint = self.blueprint_system.create_blueprint(
            self.factory, name, description
        )
        share_code = blueprint['share_code']
        return share_code  # Can be posted online, imported by others

# Usage
game = CompleteOptimizationGame()

# Game loop
while running:
    game.update(dt)
    game.render()
    handle_input()

# Result: Optimization IS the game

Implementation Checklist

  • Visible metrics (throughput, efficiency, bottlenecks)
  • Status indicators on all buildings
  • Bottleneck detection system
  • Visual bottleneck highlighting
  • Multiple optimization dimensions (speed/cost/space/power)
  • Tradeoff design (no single best solution)
  • Satisfying visual feedback (flow animations)
  • Satisfying audio feedback (production sounds)
  • Milestone celebration system
  • Real-time statistics dashboard
  • Progressive complexity (tutorial → endgame)
  • Complexity gating (unlock gradually)
  • In-game ratio calculator
  • Test bench / sandbox mode
  • Blueprint system (save/load designs)
  • Refund on deconstruction (encourage iteration)
  • Challenge system
  • Leaderboards (multiple dimensions)
  • Sharing system (blueprint codes)
  • Before/after comparison tool

This skill document provides production-ready patterns for making optimization itself the core gameplay loop. The key insight is that optimization becomes play when it's visible, satisfying, and opens up creative expression rather than following predetermined solutions.

Go build factories that players can't stop optimizing.