SimFactory2 / index.html
awacke1's picture
Update index.html
9541dc1 verified
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Factory Game</title>
<script type="module" crossorigin src="https://cdn.jsdelivr.net/npm/@gradio/lite/dist/lite.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@gradio/lite/dist/lite.css" />
<style>
html, body {
margin: 0;
padding: 0;
height: 100%;
}
</style>
</head>
<body>
<gradio-lite>
<gradio-file name="app.py" entrypoint>
import gradio as gr
import json
GRID_SIZE = 8
class GameState:
def __init__(self):
self.resources = {
"energy": 50,
"minerals": 50,
"circuits": 0
}
self.grid = [[None for _ in range(GRID_SIZE)] for _ in range(GRID_SIZE)]
self.message = ""
def to_json(self):
return json.dumps({
"resources": self.resources,
"grid": self.grid,
"message": self.message
})
def process_click(row, col, building_type, state_json):
if not state_json:
return GameState().to_json()
state = json.loads(state_json)
game = GameState()
game.resources = state["resources"]
game.grid = state["grid"]
# Building costs
costs = {
"solarPanel": {"minerals": 10},
"mineralExtractor": {"energy": 10},
"circuitFactory": {"energy": 15, "minerals": 15}
}
# Check if we can afford the building
if building_type in costs:
can_afford = True
for resource, cost in costs[building_type].items():
if game.resources[resource] < cost:
can_afford = False
game.message = f"Not enough {resource}!"
break
if can_afford:
# Deduct resources
for resource, cost in costs[building_type].items():
game.resources[resource] -= cost
# Place building
if game.grid[row][col] is None:
game.grid[row][col] = building_type
game.message = f"Placed {building_type}"
else:
game.message = "Space already occupied!"
# Produce resources from buildings
for r in range(GRID_SIZE):
for c in range(GRID_SIZE):
building = game.grid[r][c]
if building == "solarPanel":
game.resources["energy"] += 1
elif building == "mineralExtractor":
game.resources["minerals"] += 1
elif building == "circuitFactory":
game.resources["circuits"] += 1
return game.to_json()
def create_ui():
building_colors = {
"solarPanel": "#FEF08A",
"mineralExtractor": "#D1D5DB",
"circuitFactory": "#BBF7D0"
}
html = f"""
<div style="max-width: 800px; margin: 0 auto; padding: 1rem;">
<div id="resources" style="display: grid; grid-template-columns: repeat(3, 1fr); gap: 1rem; margin-bottom: 1rem;">
<div style="padding: 0.75rem; border-radius: 0.5rem; background: #FEF9C3;">Energy: <span id="energy">50</span></div>
<div style="padding: 0.75rem; border-radius: 0.5rem; background: #F3F4F6;">Minerals: <span id="minerals">50</span></div>
<div style="padding: 0.75rem; border-radius: 0.5rem; background: #DCFCE7;">Circuits: <span id="circuits">0</span></div>
</div>
<div style="display: flex; gap: 1rem; margin-bottom: 1rem;">
<button onclick="window.selectedBuilding='solarPanel'" style="padding: 1rem; border-radius: 0.5rem; background: #FEF08A;">
Solar Panel<br>Cost: 10 minerals
</button>
<button onclick="window.selectedBuilding='mineralExtractor'" style="padding: 1rem; border-radius: 0.5rem; background: #D1D5DB;">
Mineral Extractor<br>Cost: 10 energy
</button>
<button onclick="window.selectedBuilding='circuitFactory'" style="padding: 1rem; border-radius: 0.5rem; background: #BBF7D0;">
Circuit Factory<br>Cost: 15 energy, 15 minerals
</button>
</div>
<div id="message" style="text-align: center; color: #2563EB; font-weight: 500; margin: 0.5rem 0;"></div>
<div id="grid" style="display: grid; grid-template-columns: repeat({GRID_SIZE}, 1fr); gap: 0.25rem; background: #F3F4F6; padding: 0.5rem; border-radius: 0.5rem;">
{''''.join(f'''
<button
onclick="placeBuilding({r}, {c})"
id="cell-{r}-{c}"
style="aspect-ratio: 1; border-radius: 0.5rem; border: none; cursor: pointer; background: white;">
</button>
''' for r in range(GRID_SIZE) for c in range(GRID_SIZE))}
</div>
</div>
<script>
window.selectedBuilding = null;
window.gameState = null;
function updateUI(state) {
window.gameState = state;
// Update resources
document.getElementById('energy').textContent = state.resources.energy;
document.getElementById('minerals').textContent = state.resources.minerals;
document.getElementById('circuits').textContent = state.resources.circuits;
// Update grid
for (let r = 0; r < {GRID_SIZE}; r++) {{
for (let c = 0; c < {GRID_SIZE}; c++) {{
const cell = document.getElementById(`cell-${{r}}-${{c}}`);
const building = state.grid[r][c];
cell.style.background = building ? buildingColors[building] : 'white';
}}
}}
// Update message
document.getElementById('message').textContent = state.message;
}}
const buildingColors = {json.dumps(building_colors)};
function placeBuilding(row, col) {{
if (!window.selectedBuilding) {{
document.getElementById('message').textContent = 'Select a building first!';
return;
}}
send_click(row, col, window.selectedBuilding, JSON.stringify(window.gameState));
}}
// Production tick
setInterval(() => {{
if (window.gameState) {{
send_click(-1, -1, null, JSON.stringify(window.gameState));
}}
}}, 1000);
</script>
"""
return gr.HTML(html)
with gr.Blocks() as demo:
state = gr.State()
click_handler = gr.Interface(
fn=process_click,
inputs=[
gr.Number(label="Row"),
gr.Number(label="Col"),
gr.Text(label="Building"),
gr.Text(label="State")
],
outputs=gr.Text(label="New State"),
live=True
)
ui = create_ui()
def update_ui(value):
return value
click_handler.load(lambda: GameState().to_json())
demo.load(lambda: None, None, _js="() => { window.send_click = (row, col, building, state) => { "+click_handler.jsfn+"(row, col, building, state).then((v) => updateUI(JSON.parse(v))) } }")
demo.launch()
</gradio-file>
<gradio-requirements>
</gradio-requirements>
</gradio-lite>
</body>
</html>