awacke1 commited on
Commit
9d12910
ยท
verified ยท
1 Parent(s): a59f32b

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +70 -57
app.py CHANGED
@@ -2,11 +2,12 @@ import streamlit as st
2
  from streamlit.components.v1 import html
3
  import random
4
  import json
 
5
 
6
  # Shared state for multiplayer
7
  if 'game_state' not in st.session_state:
8
  st.session_state.game_state = {
9
- 'grid': [['empty' for _ in range(15)] for _ in range(20)],
10
  'buildings': [],
11
  'players': {},
12
  'train': {'x': 0, 'y': 5 * 40, 'dir': 1},
@@ -56,10 +57,10 @@ plants = ["๐ŸŒฑ", "๐ŸŒฒ", "๐ŸŒณ", "๐ŸŒด", "๐ŸŒต", "๐ŸŒพ", "๐ŸŒฟ", "๐Ÿ€", "๐Ÿ"
56
  buildings = ["๐Ÿ ", "๐Ÿก", "๐Ÿข", "๐Ÿฃ", "๐Ÿค", "๐Ÿฅ", "๐Ÿฆ", "๐Ÿจ", "๐Ÿฉ", "๐Ÿช"]
57
  creatures = ["๐Ÿพ", "๐Ÿฑ", "๐Ÿถ", "๐Ÿญ", "๐Ÿฐ", "๐ŸฆŠ", "๐Ÿป", "๐Ÿท", "๐Ÿฎ", "๐Ÿธ"]
58
 
59
- # p5.js code
60
  p5js_code = """
61
- let gridSize = 40;
62
- let grid = [];
63
  let buildings = [];
64
  let train = { x: 0, y: 0, dir: 1 };
65
  let monsterMode = false;
@@ -68,10 +69,11 @@ let monsterX, monsterY;
68
  let angle = PI / 6;
69
  let debugText = "Loading...";
70
  let playerId = null;
 
71
 
72
  function setup() {
73
  createCanvas(800, 600);
74
- grid = JSON.parse(document.getElementById('game_state').innerHTML);
75
  buildings = JSON.parse(document.getElementById('buildings').innerHTML);
76
  train = JSON.parse(document.getElementById('train').innerHTML);
77
  monsterMode = JSON.parse(document.getElementById('monster_mode').innerHTML);
@@ -80,11 +82,15 @@ function setup() {
80
  monsterY = parseInt(document.getElementById('monster_y').innerHTML);
81
  playerId = document.getElementById('player_id').innerHTML;
82
  debugText = `Player ${playerId} joined. Click to build!`;
 
 
 
 
83
  }
84
 
85
  function draw() {
86
  background(220);
87
- drawGrid();
88
  drawBuildings();
89
  drawTrain();
90
  if (monsterMode) drawMonster();
@@ -93,23 +99,23 @@ function draw() {
93
  text(debugText, 10, 20);
94
  }
95
 
96
- function drawGrid() {
97
- for (let i = 0; i < grid.length; i++) {
98
- for (let j = 0; j < grid[i].length; j++) {
99
- let x = i * gridSize;
100
- let y = j * gridSize;
101
- let z = j * gridSize * sin(angle);
102
- fill(grid[i][j] === 'track' ? 100 : 150, 200, 150);
103
  stroke(0);
104
  beginShape();
105
- vertex(x, y - z);
106
- vertex(x + gridSize, y - z);
107
- vertex(x + gridSize * cos(angle), y + gridSize * sin(angle) - z);
108
- vertex(x + gridSize * (1 - cos(angle)), y + gridSize * sin(angle) - z);
109
  endShape(CLOSE);
110
- if (grid[i][j] !== 'empty' && grid[i][j] !== 'track') {
111
  textSize(20);
112
- text(grid[i][j], x + 10, y + 20 - z);
113
  }
114
  }
115
  }
@@ -117,9 +123,9 @@ function drawGrid() {
117
 
118
  function drawBuildings() {
119
  buildings.forEach(b => {
120
- let x = b.x * gridSize;
121
- let y = b.y * gridSize;
122
- let z = b.y * gridSize * sin(angle);
123
  fill(b.color);
124
  noStroke();
125
  beginShape();
@@ -190,10 +196,10 @@ function drawMonster() {
190
  }
191
 
192
  function mousePressed() {
193
- let i = floor(mouseX / gridSize);
194
- let j = floor(mouseY / gridSize);
195
- if (i >= 0 && i < grid.length && j >= 0 && j < grid[0].length) {
196
- if (grid[i][j] === 'empty' && !monsterMode) {
197
  let selectedEmoji = document.getElementById('selected_emoji').innerHTML;
198
  if (selectedEmoji.startsWith('๐Ÿ ') || selectedEmoji.startsWith('๐Ÿก') || selectedEmoji.startsWith('๐Ÿข') ||
199
  selectedEmoji.startsWith('๐Ÿฃ') || selectedEmoji.startsWith('๐Ÿค') || selectedEmoji.startsWith('๐Ÿฅ') ||
@@ -202,10 +208,11 @@ function mousePressed() {
202
  let types = ['Residential', 'Commercial', 'Industrial', 'School', 'PowerPlant'];
203
  let colors = [[0, 200, 0], [0, 0, 200], [200, 200, 0], [200, 0, 200], [100, 100, 100]];
204
  let idx = floor(random(5));
205
- buildings.push({ x: i, y: j, type: types[idx], color: colors[idx] });
206
- grid[i][j] = 'building';
207
  } else {
208
- grid[i][j] = selectedEmoji;
 
209
  }
210
  debugText = `Player ${playerId} placed ${selectedEmoji} at (${i}, ${j})`;
211
  updateState();
@@ -241,7 +248,7 @@ function updateState() {
241
  method: 'POST',
242
  headers: { 'Content-Type': 'application/json' },
243
  body: JSON.stringify({
244
- grid: grid,
245
  buildings: buildings,
246
  train: train,
247
  monster_mode: monsterMode,
@@ -260,16 +267,19 @@ if 'player_id' not in st.session_state:
260
  player_id = st.sidebar.selectbox("Choose Player", random_names, index=random_names.index(st.session_state.player_id))
261
  st.session_state.player_id = player_id
262
 
263
- # Story plot generator
264
- st.sidebar.subheader("๐Ÿ“œ Story Plot")
265
- story_emoji, story_text = random.choice(story_beginnings)
266
- st.sidebar.write(f"{story_emoji} {story_text} {random.choice(nature_labels)} stirred the scene.")
 
 
 
 
267
 
268
  # Palette grid
269
  st.sidebar.subheader("๐ŸŽจ Palette")
270
  cols = st.sidebar.columns(5)
271
  selected_emoji = st.session_state.get('selected_emoji', plants[0])
272
-
273
  for i, emoji in enumerate(plants + buildings + creatures):
274
  col = cols[i % 5]
275
  if col.button(emoji, key=f"emoji_{i}"):
@@ -282,27 +292,28 @@ if player_id not in st.session_state.game_state['players']:
282
  for b in st.session_state.game_state['buildings']:
283
  if b.get('player') == player_id:
284
  st.session_state.game_state['players'][player_id] += 1
285
- for i in range(len(st.session_state.game_state['grid'])):
286
- for j in range(len(st.session_state.game_state['grid'][i])):
287
- if st.session_state.game_state['grid'][i][j] not in ['empty', 'track', 'building']:
288
- if st.session_state.game_state['grid'][i][j] in plants + creatures:
289
- st.session_state.game_state['players'][player_id] += 1
290
- st.sidebar.subheader("๐Ÿ† Scores")
291
  for p, s in st.session_state.game_state['players'].items():
292
- st.sidebar.write(f"{p}: {s}")
 
 
293
 
294
- # HTML content
295
- html_content = f"""
296
  <!DOCTYPE html>
297
  <html>
298
  <head>
299
  <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.2/p5.min.js"></script>
300
  <style>
301
- body {{ font-family: Arial, sans-serif; margin: 0; padding: 20px; background: #f0f0f0; }}
302
- #controls {{ margin-bottom: 20px; }}
303
- button {{ padding: 10px 20px; margin: 5px; background: #4CAF50; color: white; border: none; border-radius: 5px; cursor: pointer; }}
304
  button:hover {{ background: #45a049; }}
305
- select {{ padding: 10px; margin: 5px; border-radius: 5px; }}
306
  </style>
307
  </head>
308
  <body>
@@ -315,7 +326,7 @@ html_content = f"""
315
  <button onclick="reverseTrain()">Reverse Train (T)</button>
316
  </div>
317
  <div id="sketch-holder"></div>
318
- <div id="game_state" style="display:none">{json.dumps(st.session_state.game_state['grid'])}</div>
319
  <div id="buildings" style="display:none">{json.dumps(st.session_state.game_state['buildings'])}</div>
320
  <div id="train" style="display:none">{json.dumps(st.session_state.game_state['train'])}</div>
321
  <div id="monster_mode" style="display:none">{json.dumps(st.session_state.game_state['monster_mode'])}</div>
@@ -336,16 +347,14 @@ html_content = f"""
336
  </html>
337
  """
338
 
339
- # Streamlit app
340
- st.title("SimCity 2000 Multiplayer Adventure")
341
  st.write(f"Player: {player_id}. Click to place {selected_emoji}. Use M/G/R/T keys.")
 
342
 
343
- html(html_content, height=700)
344
-
345
- # Note: Streamlit doesn't natively support POST endpoints, so this is a placeholder for state update logic
346
- # In a real app, you'd need a backend (e.g., Flask) to handle POST requests for true multiplayer sync
347
  def update_state(data):
348
- st.session_state.game_state['grid'] = data['grid']
349
  st.session_state.game_state['buildings'] = data['buildings']
350
  st.session_state.game_state['train'] = data['train']
351
  st.session_state.game_state['monster_mode'] = data['monster_mode']
@@ -355,4 +364,8 @@ def update_state(data):
355
  if data['player_id'] not in st.session_state.game_state['players']:
356
  st.session_state.game_state['players'][data['player_id']] = 0
357
  st.session_state.game_state['players'][data['player_id']] += 1
358
- st.rerun()
 
 
 
 
 
2
  from streamlit.components.v1 import html
3
  import random
4
  import json
5
+ import math
6
 
7
  # Shared state for multiplayer
8
  if 'game_state' not in st.session_state:
9
  st.session_state.game_state = {
10
+ 'hex_grid': [[{'type': 'empty', 'emoji': ''} for _ in range(15)] for _ in range(20)], # 20x15 hex grid
11
  'buildings': [],
12
  'players': {},
13
  'train': {'x': 0, 'y': 5 * 40, 'dir': 1},
 
57
  buildings = ["๐Ÿ ", "๐Ÿก", "๐Ÿข", "๐Ÿฃ", "๐Ÿค", "๐Ÿฅ", "๐Ÿฆ", "๐Ÿจ", "๐Ÿฉ", "๐Ÿช"]
58
  creatures = ["๐Ÿพ", "๐Ÿฑ", "๐Ÿถ", "๐Ÿญ", "๐Ÿฐ", "๐ŸฆŠ", "๐Ÿป", "๐Ÿท", "๐Ÿฎ", "๐Ÿธ"]
59
 
60
+ # p5.js code for hex grid and gameplay
61
  p5js_code = """
62
+ let hexSize = 40;
63
+ let hexGrid = [];
64
  let buildings = [];
65
  let train = { x: 0, y: 0, dir: 1 };
66
  let monsterMode = false;
 
69
  let angle = PI / 6;
70
  let debugText = "Loading...";
71
  let playerId = null;
72
+ const sqrt3 = Math.sqrt(3);
73
 
74
  function setup() {
75
  createCanvas(800, 600);
76
+ hexGrid = JSON.parse(document.getElementById('game_state').innerHTML);
77
  buildings = JSON.parse(document.getElementById('buildings').innerHTML);
78
  train = JSON.parse(document.getElementById('train').innerHTML);
79
  monsterMode = JSON.parse(document.getElementById('monster_mode').innerHTML);
 
82
  monsterY = parseInt(document.getElementById('monster_y').innerHTML);
83
  playerId = document.getElementById('player_id').innerHTML;
84
  debugText = `Player ${playerId} joined. Click to build!`;
85
+ // Set train track on row 5
86
+ for (let i = 0; i < hexGrid.length; i++) {
87
+ hexGrid[i][5].type = 'track';
88
+ }
89
  }
90
 
91
  function draw() {
92
  background(220);
93
+ drawHexGrid();
94
  drawBuildings();
95
  drawTrain();
96
  if (monsterMode) drawMonster();
 
99
  text(debugText, 10, 20);
100
  }
101
 
102
+ function drawHexGrid() {
103
+ for (let i = 0; i < hexGrid.length; i++) {
104
+ for (let j = 0; j < hexGrid[i].length; j++) {
105
+ let x = i * hexSize * 1.5;
106
+ let y = j * hexSize * sqrt3 + (i % 2 === 1 ? hexSize * sqrt3 / 2 : 0);
107
+ let z = j * hexSize * sin(angle);
108
+ fill(hexGrid[i][j].type === 'track' ? 100 : 150, 200, 150);
109
  stroke(0);
110
  beginShape();
111
+ for (let k = 0; k < 6; k++) {
112
+ let angleRad = PI / 3 * k;
113
+ vertex(x + hexSize * cos(angleRad), y + hexSize * sin(angleRad) - z);
114
+ }
115
  endShape(CLOSE);
116
+ if (hexGrid[i][j].emoji) {
117
  textSize(20);
118
+ text(hexGrid[i][j].emoji, x - 10, y + 5 - z);
119
  }
120
  }
121
  }
 
123
 
124
  function drawBuildings() {
125
  buildings.forEach(b => {
126
+ let x = b.x * hexSize * 1.5;
127
+ let y = b.y * hexSize * sqrt3 + (b.x % 2 === 1 ? hexSize * sqrt3 / 2 : 0);
128
+ let z = b.y * hexSize * sin(angle);
129
  fill(b.color);
130
  noStroke();
131
  beginShape();
 
196
  }
197
 
198
  function mousePressed() {
199
+ let i = floor(mouseX / (hexSize * 1.5));
200
+ let j = floor((mouseY - (i % 2 === 1 ? hexSize * sqrt3 / 2 : 0)) / (hexSize * sqrt3));
201
+ if (i >= 0 && i < hexGrid.length && j >= 0 && j < hexGrid[0].length) {
202
+ if (hexGrid[i][j].type === 'empty' && !monsterMode) {
203
  let selectedEmoji = document.getElementById('selected_emoji').innerHTML;
204
  if (selectedEmoji.startsWith('๐Ÿ ') || selectedEmoji.startsWith('๐Ÿก') || selectedEmoji.startsWith('๐Ÿข') ||
205
  selectedEmoji.startsWith('๐Ÿฃ') || selectedEmoji.startsWith('๐Ÿค') || selectedEmoji.startsWith('๐Ÿฅ') ||
 
208
  let types = ['Residential', 'Commercial', 'Industrial', 'School', 'PowerPlant'];
209
  let colors = [[0, 200, 0], [0, 0, 200], [200, 200, 0], [200, 0, 200], [100, 100, 100]];
210
  let idx = floor(random(5));
211
+ buildings.push({ x: i, y: j, type: types[idx], color: colors[idx], player: playerId });
212
+ hexGrid[i][j].type = 'building';
213
  } else {
214
+ hexGrid[i][j].type = 'placed';
215
+ hexGrid[i][j].emoji = selectedEmoji;
216
  }
217
  debugText = `Player ${playerId} placed ${selectedEmoji} at (${i}, ${j})`;
218
  updateState();
 
248
  method: 'POST',
249
  headers: { 'Content-Type': 'application/json' },
250
  body: JSON.stringify({
251
+ hex_grid: hexGrid,
252
  buildings: buildings,
253
  train: train,
254
  monster_mode: monsterMode,
 
267
  player_id = st.sidebar.selectbox("Choose Player", random_names, index=random_names.index(st.session_state.player_id))
268
  st.session_state.player_id = player_id
269
 
270
+ # Story plot generator panel
271
+ story_html = f"""
272
+ <div style='background: #f9f9f9; padding: 10px; border-radius: 5px; margin-bottom: 10px;'>
273
+ <h3>๐Ÿ“œ Story Plot</h3>
274
+ <p>{random.choice(story_beginnings)[1]} {random.choice(nature_labels)} stirred the scene.</p>
275
+ </div>
276
+ """
277
+ st.sidebar.markdown(story_html, unsafe_allow_html=True)
278
 
279
  # Palette grid
280
  st.sidebar.subheader("๐ŸŽจ Palette")
281
  cols = st.sidebar.columns(5)
282
  selected_emoji = st.session_state.get('selected_emoji', plants[0])
 
283
  for i, emoji in enumerate(plants + buildings + creatures):
284
  col = cols[i % 5]
285
  if col.button(emoji, key=f"emoji_{i}"):
 
292
  for b in st.session_state.game_state['buildings']:
293
  if b.get('player') == player_id:
294
  st.session_state.game_state['players'][player_id] += 1
295
+ for i in range(len(st.session_state.game_state['hex_grid'])):
296
+ for j in range(len(st.session_state.game_state['hex_grid'][i])):
297
+ if st.session_state.game_state['hex_grid'][i][j]['type'] == 'placed':
298
+ st.session_state.game_state['players'][player_id] += 1
299
+ score_html = "<div style='background: #f9f9f9; padding: 10px; border-radius: 5px;'><h3>๐Ÿ† Scores</h3><ul>"
 
300
  for p, s in st.session_state.game_state['players'].items():
301
+ score_html += f"<li>{p}: {s}</li>"
302
+ score_html += "</ul></div>"
303
+ st.sidebar.markdown(score_html, unsafe_allow_html=True)
304
 
305
+ # Main game panel
306
+ game_html = f"""
307
  <!DOCTYPE html>
308
  <html>
309
  <head>
310
  <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.2/p5.min.js"></script>
311
  <style>
312
+ body {{ font-family: Arial, sans-serif; margin: 0; padding: 0; background: #f0f0f0; }}
313
+ #controls {{ padding: 10px; background: #e0e0e0; }}
314
+ button {{ padding: 8px 16px; margin: 5px; background: #4CAF50; color: white; border: none; border-radius: 5px; cursor: pointer; }}
315
  button:hover {{ background: #45a049; }}
316
+ select {{ padding: 8px; margin: 5px; border-radius: 5px; }}
317
  </style>
318
  </head>
319
  <body>
 
326
  <button onclick="reverseTrain()">Reverse Train (T)</button>
327
  </div>
328
  <div id="sketch-holder"></div>
329
+ <div id="game_state" style="display:none">{json.dumps(st.session_state.game_state['hex_grid'])}</div>
330
  <div id="buildings" style="display:none">{json.dumps(st.session_state.game_state['buildings'])}</div>
331
  <div id="train" style="display:none">{json.dumps(st.session_state.game_state['train'])}</div>
332
  <div id="monster_mode" style="display:none">{json.dumps(st.session_state.game_state['monster_mode'])}</div>
 
347
  </html>
348
  """
349
 
350
+ # Streamlit app layout
351
+ st.title("HexCity 2000 Multiplayer Adventure")
352
  st.write(f"Player: {player_id}. Click to place {selected_emoji}. Use M/G/R/T keys.")
353
+ html(game_html, height=650)
354
 
355
+ # Update state function (mocked for Streamlit)
 
 
 
356
  def update_state(data):
357
+ st.session_state.game_state['hex_grid'] = data['hex_grid']
358
  st.session_state.game_state['buildings'] = data['buildings']
359
  st.session_state.game_state['train'] = data['train']
360
  st.session_state.game_state['monster_mode'] = data['monster_mode']
 
364
  if data['player_id'] not in st.session_state.game_state['players']:
365
  st.session_state.game_state['players'][data['player_id']] = 0
366
  st.session_state.game_state['players'][data['player_id']] += 1
367
+ st.rerun()
368
+
369
+ # Mock POST handler (for debugging)
370
+ if st.session_state.get('last_update'):
371
+ update_state(st.session_state['last_update'])