Spaces:
Sleeping
Sleeping
| import streamlit as st | |
| import numpy as np | |
| import time | |
| from dataclasses import dataclass | |
| from typing import Dict, List, Optional | |
| class Building: | |
| name: str | |
| cost: Dict[str, int] | |
| produces: Dict[str, float] # Changed to dict for multiple outputs | |
| color: str | |
| icon: str | |
| description: str | |
| class FactoryGame: | |
| def __init__(self): | |
| self.GRID_SIZE = 8 | |
| self.buildings = { | |
| "solar_panel": Building( | |
| name="Solar Panel", | |
| cost={"minerals": 10}, | |
| produces={"electricity": 1}, | |
| color="#FEF08A", | |
| icon="โ๏ธ", | |
| description="Produces 1 electricity unit" | |
| ), | |
| "mineral_extractor": Building( | |
| name="Mineral Extractor", | |
| cost={"electricity": 2}, | |
| produces={"minerals": 1}, | |
| color="#D1D5DB", | |
| icon="โ๏ธ", | |
| description="Extracts minerals from the ground" | |
| ), | |
| "circuit_factory": Building( | |
| name="Circuit Factory", | |
| cost={"electricity": 5, "minerals": 15}, | |
| produces={"circuits": 1}, | |
| color="#BBF7D0", | |
| icon="๐ง", | |
| description="Produces electronic circuits" | |
| ), | |
| "nuclear_plant": Building( | |
| name="Nuclear Plant", | |
| cost={"minerals": 50, "circuits": 20}, | |
| produces={"electricity": 10}, | |
| color="#A7F3D0", | |
| icon="โ๏ธ", | |
| description="Produces 10 electricity units" | |
| ), | |
| "gpu_factory": Building( | |
| name="GPU Factory", | |
| cost={"circuits": 30, "minerals": 40}, | |
| produces={"tflops": 100, "electricity": -5}, # Negative for consumption | |
| color="#C7D2FE", | |
| icon="๐ฎ", | |
| description="Produces 100 TFLOPS, consumes 5 electricity" | |
| ) | |
| } | |
| # Initialize session state if needed | |
| if "resources" not in st.session_state: | |
| st.session_state.resources = { | |
| "electricity": 50, | |
| "minerals": 50, | |
| "circuits": 0, | |
| "tflops": 0 | |
| } | |
| if "grid" not in st.session_state: | |
| st.session_state.grid = [[None for _ in range(self.GRID_SIZE)] | |
| for _ in range(self.GRID_SIZE)] | |
| if "last_update" not in st.session_state: | |
| st.session_state.last_update = time.time() | |
| if "selected_building" not in st.session_state: | |
| st.session_state.selected_building = None | |
| def update_resources(self): | |
| current_time = time.time() | |
| elapsed = current_time - st.session_state.last_update | |
| if elapsed >= 1.0: # Update every second | |
| new_resources = st.session_state.resources.copy() | |
| # First calculate total electricity production/consumption | |
| electricity_delta = 0 | |
| for row in range(self.GRID_SIZE): | |
| for col in range(self.GRID_SIZE): | |
| building_id = st.session_state.grid[row][col] | |
| if building_id: | |
| building = self.buildings[building_id] | |
| if "electricity" in building.produces: | |
| electricity_delta += building.produces["electricity"] | |
| # Only run other production if we have enough electricity | |
| if new_resources["electricity"] + electricity_delta >= 0: | |
| new_resources["electricity"] += electricity_delta | |
| for row in range(self.GRID_SIZE): | |
| for col in range(self.GRID_SIZE): | |
| building_id = st.session_state.grid[row][col] | |
| if building_id: | |
| building = self.buildings[building_id] | |
| for resource, amount in building.produces.items(): | |
| if resource != "electricity": # Already handled above | |
| new_resources[resource] += amount | |
| st.session_state.resources = new_resources | |
| st.session_state.last_update = current_time | |
| def can_afford(self, building_id: str) -> bool: | |
| building = self.buildings[building_id] | |
| for resource, cost in building.cost.items(): | |
| if st.session_state.resources.get(resource, 0) < cost: | |
| return False | |
| return True | |
| def place_building(self, row: int, col: int, building_id: str) -> bool: | |
| if not self.can_afford(building_id): | |
| return False | |
| if st.session_state.grid[row][col] is not None: | |
| return False | |
| # Deduct costs | |
| building = self.buildings[building_id] | |
| for resource, cost in building.cost.items(): | |
| st.session_state.resources[resource] -= cost | |
| # Place building | |
| st.session_state.grid[row][col] = building_id | |
| return True | |
| def select_building(building_id: str): | |
| st.session_state.selected_building = building_id | |
| def handle_cell_click(row: int, col: int, game: FactoryGame): | |
| if st.session_state.selected_building: | |
| game.place_building(row, col, st.session_state.selected_building) | |
| def main(): | |
| st.set_page_config(page_title="Factory Game", layout="wide") | |
| game = FactoryGame() | |
| # Title | |
| st.title("๐ญ Factory Game", anchor=False) | |
| # Layout columns | |
| col1, col2 = st.columns([3, 1]) | |
| with col2: | |
| # Resources display | |
| st.subheader("Resources") | |
| col_a, col_b = st.columns(2) | |
| with col_a: | |
| st.metric("โก Power", f"{int(st.session_state.resources['electricity'])}") | |
| st.metric("๐ชจ Minerals", f"{int(st.session_state.resources['minerals'])}") | |
| with col_b: | |
| st.metric("๐ Circuits", f"{int(st.session_state.resources['circuits'])}") | |
| st.metric("๐ป TFLOPS", f"{int(st.session_state.resources['tflops'])}") | |
| # Building selection | |
| st.subheader("Buildings") | |
| for building_id, building in game.buildings.items(): | |
| if st.button( | |
| f"{building.icon} {building.name}\n" | |
| f"Cost: {', '.join(f'{cost} {res}' for res, cost in building.cost.items())}", | |
| help=building.description, | |
| key=f"building_{building_id}", | |
| type="secondary" if st.session_state.selected_building != building_id else "primary" | |
| ): | |
| select_building(building_id) | |
| st.caption(f"Selected: {game.buildings[st.session_state.selected_building].icon if st.session_state.selected_building else 'None'}") | |
| with col1: | |
| # Game grid with minimal spacing | |
| grid_container = st.container() | |
| with grid_container: | |
| for row in range(game.GRID_SIZE): | |
| cols = st.columns(game.GRID_SIZE) | |
| for col, column in enumerate(cols): | |
| building_id = st.session_state.grid[row][col] | |
| building = game.buildings.get(building_id) if building_id else None | |
| # Just show the emoji, no labels | |
| label = building.icon if building else "โฌ" | |
| with column: | |
| if st.button( | |
| label, | |
| key=f"cell_{row}_{col}", | |
| help=building.name if building else "Empty space", | |
| use_container_width=True | |
| ): | |
| handle_cell_click(row, col, game) | |
| # Update resources periodically | |
| game.update_resources() | |
| # Force a rerun every second to update resources | |
| time.sleep(0.1) | |
| st.rerun() | |
| if __name__ == "__main__": | |
| main() |