awacke1 commited on
Commit
a59f32b
·
verified ·
1 Parent(s): c1b75cc

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +175 -51
app.py CHANGED
@@ -1,7 +1,62 @@
1
  import streamlit as st
2
  from streamlit.components.v1 import html
 
 
3
 
4
- # Define the p5.js sketch code as a string
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5
  p5js_code = """
6
  let gridSize = 40;
7
  let grid = [];
@@ -10,25 +65,21 @@ let train = { x: 0, y: 0, dir: 1 };
10
  let monsterMode = false;
11
  let currentMonster = 'Godzilla';
12
  let monsterX, monsterY;
13
- let angle = PI / 6; // 3D perspective angle
14
  let debugText = "Loading...";
 
15
 
16
  function setup() {
17
  createCanvas(800, 600);
18
- for (let i = 0; i < width / gridSize; i++) {
19
- grid[i] = [];
20
- for (let j = 0; j < height / gridSize; j++) {
21
- grid[i][j] = 'empty';
22
- }
23
- }
24
- for (let i = 0; i < width / gridSize; i++) {
25
- grid[i][5] = 'track';
26
- }
27
- train.x = 0;
28
- train.y = 5 * gridSize;
29
- monsterX = width / 2;
30
- monsterY = height / 2;
31
- debugText = "Setup complete. Click to build, use M/G/R/T keys.";
32
  }
33
 
34
  function draw() {
@@ -38,7 +89,8 @@ function draw() {
38
  drawTrain();
39
  if (monsterMode) drawMonster();
40
  fill(0);
41
- text(debugText, 10, 20); // Debug feedback
 
42
  }
43
 
44
  function drawGrid() {
@@ -55,6 +107,10 @@ function drawGrid() {
55
  vertex(x + gridSize * cos(angle), y + gridSize * sin(angle) - z);
56
  vertex(x + gridSize * (1 - cos(angle)), y + gridSize * sin(angle) - z);
57
  endShape(CLOSE);
 
 
 
 
58
  }
59
  }
60
  }
@@ -138,12 +194,21 @@ function mousePressed() {
138
  let j = floor(mouseY / gridSize);
139
  if (i >= 0 && i < grid.length && j >= 0 && j < grid[0].length) {
140
  if (grid[i][j] === 'empty' && !monsterMode) {
141
- let types = ['Residential', 'Commercial', 'Industrial', 'School', 'PowerPlant'];
142
- let colors = [[0, 200, 0], [0, 0, 200], [200, 200, 0], [200, 0, 200], [100, 100, 100]];
143
- let idx = floor(random(5));
144
- buildings.push({ x: i, y: j, type: types[idx], color: colors[idx] });
145
- grid[i][j] = 'building';
146
- debugText = `Placed ${types[idx]} at (${i}, ${j})`;
 
 
 
 
 
 
 
 
 
147
  }
148
  }
149
  }
@@ -152,36 +217,81 @@ function keyPressed() {
152
  if (key === 'm' || key === 'M') {
153
  monsterMode = !monsterMode;
154
  debugText = `Monster Mode: ${monsterMode}`;
 
155
  }
156
  if (key === 'g' || key === 'G') {
157
  currentMonster = 'Godzilla';
158
  debugText = "Monster set to Godzilla";
 
159
  }
160
  if (key === 'r' || key === 'R') {
161
  currentMonster = 'GiantRobot';
162
  debugText = "Monster set to Giant Robot";
 
163
  }
164
  if (key === 't' || key === 'T') {
165
  train.dir *= -1;
166
  debugText = "Train direction reversed";
 
167
  }
168
  }
169
 
170
- window.toggleMonsterMode = function() {
171
- monsterMode = !monsterMode;
172
- debugText = `Monster Mode: ${monsterMode}`;
173
- };
174
- window.setMonster = function(monster) {
175
- currentMonster = monster;
176
- debugText = `Monster set to ${monster}`;
177
- };
178
- window.reverseTrain = function() {
179
- train.dir *= -1;
180
- debugText = "Train direction reversed";
181
- };
 
 
 
 
182
  """
183
 
184
- # Full HTML content with embedded p5.js
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
185
  html_content = f"""
186
  <!DOCTYPE html>
187
  <html>
@@ -205,6 +315,15 @@ html_content = f"""
205
  <button onclick="reverseTrain()">Reverse Train (T)</button>
206
  </div>
207
  <div id="sketch-holder"></div>
 
 
 
 
 
 
 
 
 
208
 
209
  <script>
210
  {p5js_code}
@@ -217,18 +336,23 @@ html_content = f"""
217
  </html>
218
  """
219
 
220
- # Streamlit app with sidebar
221
- st.title("SimCity 2000 with Monster Mode")
222
- st.write("Click to place buildings. Use keys: M (monster), G (Godzilla), R (Robot), T (train reverse).")
223
-
224
- # Sidebar with emoji-grouped info (no JS calls)
225
- with st.sidebar:
226
- st.header("Controls")
227
- st.subheader("🏡 Buildings")
228
- st.write("Click to randomly place: Residential, Commercial, Industrial, School, Power Plant")
229
- st.subheader("👾 Monsters")
230
- st.write("M: Toggle Monster Mode\nG: Godzilla\nR: Giant Robot")
231
- st.subheader("🚂 Train")
232
- st.write("T: Reverse Train Direction")
233
-
234
- html(html_content, height=700)
 
 
 
 
 
 
1
  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},
13
+ 'monster_mode': False,
14
+ 'current_monster': 'Godzilla',
15
+ 'monster_x': 400,
16
+ 'monster_y': 300
17
+ }
18
+
19
+ # Random player names
20
+ random_names = [
21
+ "SkyWalker", "ForestRanger", "CityBuilder", "MonsterTamer", "RailMaster",
22
+ "PlantWhisperer", "UrbanWizard", "NatureSage", "GridLord", "EcoWarrior"
23
+ ]
24
+
25
+ # Story plot generator beginnings
26
+ story_beginnings = [
27
+ ("🏠", "In a bustling city nestled between towering mountains,"),
28
+ ("🏃", "A lone figure darted through the streets as the sun began to set,"),
29
+ ("🧠", "Thoughts raced through their mind, planning the next move,"),
30
+ ("😲", "Shock rippled through the crowd as the ground trembled,"),
31
+ ("💬", "'We need to act now!' someone shouted over the chaos,"),
32
+ ("🔍", "A closer look revealed hidden secrets in the city’s core,"),
33
+ ("🎬", "A train screeched into the station, unloading its mysteries,"),
34
+ ("🏞️", "Lush greenery framed the skyline, a stark contrast to the urban sprawl,"),
35
+ ("⏩", "Events unfolded rapidly, leaving no time to breathe,"),
36
+ ("👁️", "The horizon glowed with an eerie, captivating light,"),
37
+ ("👂", "Whispers of wind carried tales of forgotten lands,"),
38
+ ("🗣️", "A juicy rumor spread like wildfire among the citizens,"),
39
+ ("🤸", "With a simple leap, the adventure began anew,"),
40
+ ("🧩", "The essentials of survival lay scattered across the grid,"),
41
+ ("🚶", "A slow walk revealed the city’s heartbeat,"),
42
+ ("🌊", "A journey unfolded, waves of change crashing in,"),
43
+ ("🎯", "Focus sharpened as the goal came into view,"),
44
+ ("🤔", "Neurotic thoughts plagued the planner’s restless mind,")
45
+ ]
46
+
47
+ # Witty nature labels
48
+ nature_labels = [
49
+ "Whispering Winds", "Sassy Sunlight", "Grumpy Gravel", "Chatty Clouds",
50
+ "Pensive Pines", "Witty Wetlands", "Sneaky Streams", "Bouncy Breezes",
51
+ "Daring Dewdrops", "Cheeky Crags"
52
+ ]
53
+
54
+ # Emoji palette
55
+ plants = ["🌱", "🌲", "🌳", "🌴", "🌵", "🌾", "🌿", "🍀", "🍁", "🍂"]
56
+ buildings = ["🏠", "🏡", "🏢", "🏣", "🏤", "🏥", "🏦", "🏨", "🏩", "🏪"]
57
+ creatures = ["🐾", "🐱", "🐶", "🐭", "🐰", "🦊", "🐻", "🐷", "🐮", "🐸"]
58
+
59
+ # p5.js code
60
  p5js_code = """
61
  let gridSize = 40;
62
  let grid = [];
 
65
  let monsterMode = false;
66
  let currentMonster = 'Godzilla';
67
  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);
78
+ currentMonster = document.getElementById('current_monster').innerHTML;
79
+ monsterX = parseInt(document.getElementById('monster_x').innerHTML);
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() {
 
89
  drawTrain();
90
  if (monsterMode) drawMonster();
91
  fill(0);
92
+ textSize(12);
93
+ text(debugText, 10, 20);
94
  }
95
 
96
  function drawGrid() {
 
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
  }
116
  }
 
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('🏥') ||
200
+ selectedEmoji.startsWith('🏦') || selectedEmoji.startsWith('🏨') || selectedEmoji.startsWith('🏩') ||
201
+ selectedEmoji.startsWith('🏪')) {
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();
212
  }
213
  }
214
  }
 
217
  if (key === 'm' || key === 'M') {
218
  monsterMode = !monsterMode;
219
  debugText = `Monster Mode: ${monsterMode}`;
220
+ updateState();
221
  }
222
  if (key === 'g' || key === 'G') {
223
  currentMonster = 'Godzilla';
224
  debugText = "Monster set to Godzilla";
225
+ updateState();
226
  }
227
  if (key === 'r' || key === 'R') {
228
  currentMonster = 'GiantRobot';
229
  debugText = "Monster set to Giant Robot";
230
+ updateState();
231
  }
232
  if (key === 't' || key === 'T') {
233
  train.dir *= -1;
234
  debugText = "Train direction reversed";
235
+ updateState();
236
  }
237
  }
238
 
239
+ function updateState() {
240
+ fetch('/update_state', {
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,
248
+ current_monster: currentMonster,
249
+ monster_x: monsterX,
250
+ monster_y: monsterY,
251
+ player_id: playerId
252
+ })
253
+ });
254
+ }
255
  """
256
 
257
+ # Player selection
258
+ if 'player_id' not in st.session_state:
259
+ st.session_state.player_id = random.choice(random_names)
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}"):
276
+ st.session_state.selected_emoji = emoji
277
+ selected_emoji = emoji
278
+
279
+ # Scoreboard
280
+ if player_id not in st.session_state.game_state['players']:
281
+ st.session_state.game_state['players'][player_id] = 0
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>
 
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>
322
+ <div id="current_monster" style="display:none">{st.session_state.game_state['current_monster']}</div>
323
+ <div id="monster_x" style="display:none">{st.session_state.game_state['monster_x']}</div>
324
+ <div id="monster_y" style="display:none">{st.session_state.game_state['monster_y']}</div>
325
+ <div id="player_id" style="display:none">{player_id}</div>
326
+ <div id="selected_emoji" style="display:none">{selected_emoji}</div>
327
 
328
  <script>
329
  {p5js_code}
 
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']
352
+ st.session_state.game_state['current_monster'] = data['current_monster']
353
+ st.session_state.game_state['monster_x'] = data['monster_x']
354
+ st.session_state.game_state['monster_y'] = data['monster_y']
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()