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() |