awacke1 commited on
Commit
c71868f
·
verified ·
1 Parent(s): 5175fa0

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +86 -69
app.py CHANGED
@@ -8,57 +8,71 @@ from datetime import datetime
8
  from pathlib import Path
9
  import base64
10
  from io import BytesIO
11
- from urllib.parse import urlencode
12
  import numpy as np
13
 
14
- # Constants for game board
15
  GRID_WIDTH = 16
16
  GRID_HEIGHT = 9
17
- REFRESH_RATE = 5 # seconds
18
- INTERACTION_RADIUS = 2 # tiles
19
  POINTS_PER_INTERACTION = 1
20
 
21
- # Fantasy name generator
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
22
  def generate_fantasy_name():
23
- prefixes = ['Aer', 'Bal', 'Cal', 'Dor', 'El', 'Fae', 'Gor', 'Hel', 'Il', 'Jor',
24
- 'Kal', 'Lyr', 'Mel', 'Nym', 'Oro', 'Pyr', 'Qar', 'Ryn', 'Syl', 'Tyr']
25
- suffixes = ['ian', 'or', 'ion', 'us', 'ix', 'ar', 'en', 'yr', 'el', 'an',
26
- 'is', 'ax', 'on', 'ir', 'ex', 'az', 'er', 'eth', 'ys', 'ix']
27
- return random.choice(prefixes) + random.choice(suffixes)
28
-
29
- def get_query_params():
30
- """Get game state from URL query parameters"""
31
- query_params = st.experimental_get_query_params()
32
-
33
- if 'player_name' in query_params:
34
- st.session_state.player_name = query_params['player_name'][0]
35
  st.session_state.position = {
36
- 'x': int(query_params.get('x', [random.randint(0, GRID_WIDTH - 1)])[0]),
37
- 'y': int(query_params.get('y', [random.randint(0, GRID_HEIGHT - 1)])[0])
38
  }
39
  st.session_state.character_stats = {
40
- 'STR': int(query_params.get('STR', [10])[0]),
41
- 'DEX': int(query_params.get('DEX', [10])[0]),
42
- 'CON': int(query_params.get('CON', [10])[0]),
43
- 'INT': int(query_params.get('INT', [10])[0]),
44
- 'WIS': int(query_params.get('WIS', [10])[0]),
45
- 'CHA': int(query_params.get('CHA', [10])[0]),
46
- 'HP': int(query_params.get('HP', [20])[0]),
47
- 'MAX_HP': int(query_params.get('MAX_HP', [40])[0]),
48
- 'score': int(query_params.get('score', [0])[0]),
49
- 'created_at': float(query_params.get('created_at', [time.time()])[0])
50
  }
51
 
52
- def update_query_params():
53
- """Update URL query parameters with current game state"""
54
  if st.session_state.player_name and st.session_state.character_stats:
55
  params = {
56
  'player_name': st.session_state.player_name,
57
- 'x': st.session_state.position['x'],
58
- 'y': st.session_state.position['y'],
59
- **st.session_state.character_stats
60
  }
61
- st.experimental_set_query_params(**params)
62
 
63
  # Initialize session state
64
  if 'initialized' not in st.session_state:
@@ -76,7 +90,19 @@ if 'initialized' not in st.session_state:
76
  }
77
  st.session_state.last_move = time.time()
78
  st.session_state.nearby_players = []
79
- get_query_params()
 
 
 
 
 
 
 
 
 
 
 
 
80
 
81
  def save_player_state():
82
  """Save player state to JSON file"""
@@ -91,19 +117,7 @@ def save_player_state():
91
  os.makedirs('players', exist_ok=True)
92
  with open(f"players/{st.session_state.player_name}.json", 'w') as f:
93
  json.dump(player_data, f)
94
-
95
- def load_all_players():
96
- """Load all player states from JSON files"""
97
- players = {}
98
- if os.path.exists('players'):
99
- for filename in os.listdir('players'):
100
- if filename.endswith('.json'):
101
- with open(f"players/{filename}", 'r') as f:
102
- player_data = json.load(f)
103
- # Only include active players (updated in last minute)
104
- if time.time() - player_data['last_update'] < 60:
105
- players[player_data['name']] = player_data
106
- return players
107
 
108
  def calculate_distance(pos1, pos2):
109
  """Calculate Manhattan distance between two positions with wrapping"""
@@ -124,11 +138,10 @@ def update_position(direction):
124
 
125
  st.session_state.last_move = time.time()
126
  save_player_state()
127
- update_query_params()
128
 
129
  def update_nearby_players():
130
  """Update list of nearby players and calculate score gains"""
131
- all_players = load_all_players()
132
  nearby = []
133
  score_gain = 0
134
 
@@ -146,18 +159,13 @@ def update_nearby_players():
146
  if score_gain > 0:
147
  st.session_state.character_stats['score'] += score_gain
148
  save_player_state()
149
- update_query_params()
150
 
151
  st.session_state.nearby_players = nearby
152
 
153
  def create_game_board():
154
  """Create and display the game board"""
155
- all_players = load_all_players()
156
-
157
- # Create placeholder images for tiles
158
- tile_image = Image.new('RGB', (50, 50), color='green')
159
- player_image = Image.new('RGB', (50, 50), color='blue')
160
- other_player_image = Image.new('RGB', (50, 50), color='red')
161
 
162
  # Create columns for each row
163
  for y in range(GRID_HEIGHT):
@@ -174,13 +182,13 @@ def create_game_board():
174
 
175
  # Display appropriate image and tooltip
176
  if x == st.session_state.position['x'] and y == st.session_state.position['y']:
177
- cols[x].image(player_image, use_column_width=True)
178
  cols[x].markdown(f"**You** ({st.session_state.character_stats['score']} pts)")
179
  elif player_here:
180
- cols[x].image(other_player_image, use_column_width=True)
181
  cols[x].markdown(f"**{player_here}** ({all_players[player_here]['stats']['score']} pts)")
182
  else:
183
- cols[x].image(tile_image, use_column_width=True)
184
 
185
  def main():
186
  # Update nearby players on refresh
@@ -197,9 +205,19 @@ def main():
197
  if st.sidebar.button("Start Playing"):
198
  st.session_state.player_name = player_name
199
  if st.session_state.character_stats is None:
200
- st.session_state.character_stats = roll_stats()
 
 
 
 
 
 
 
 
 
 
 
201
  save_player_state()
202
- update_query_params()
203
  st.rerun()
204
  else:
205
  # Display nearby players
@@ -226,12 +244,11 @@ def main():
226
  update_position("right")
227
  st.rerun()
228
 
229
- # Display bookmark URL
230
- st.sidebar.markdown("### Save Your Progress")
231
- st.sidebar.markdown(
232
- "Bookmark this URL to continue where you left off:"
233
- )
234
- st.sidebar.code(st.experimental_get_query_params())
235
 
236
  # Main game area
237
  st.title("Multiplayer Tile Game")
 
8
  from pathlib import Path
9
  import base64
10
  from io import BytesIO
 
11
  import numpy as np
12
 
13
+ # Constants
14
  GRID_WIDTH = 16
15
  GRID_HEIGHT = 9
16
+ REFRESH_RATE = 5
17
+ INTERACTION_RADIUS = 2
18
  POINTS_PER_INTERACTION = 1
19
 
20
+ # Singleton cache for game resources
21
+ @st.experimental_singleton
22
+ def get_game_images():
23
+ """Cache game images to improve performance"""
24
+ return {
25
+ 'tile': Image.new('RGB', (50, 50), color='green'),
26
+ 'player': Image.new('RGB', (50, 50), color='blue'),
27
+ 'other_player': Image.new('RGB', (50, 50), color='red')
28
+ }
29
+
30
+ @st.experimental_singleton
31
+ def get_name_components():
32
+ """Cache name generation components"""
33
+ return {
34
+ 'prefixes': ['Aer', 'Bal', 'Cal', 'Dor', 'El', 'Fae', 'Gor', 'Hel', 'Il', 'Jor',
35
+ 'Kal', 'Lyr', 'Mel', 'Nym', 'Oro', 'Pyr', 'Qar', 'Ryn', 'Syl', 'Tyr'],
36
+ 'suffixes': ['ian', 'or', 'ion', 'us', 'ix', 'ar', 'en', 'yr', 'el', 'an',
37
+ 'is', 'ax', 'on', 'ir', 'ex', 'az', 'er', 'eth', 'ys', 'ix']
38
+ }
39
+
40
  def generate_fantasy_name():
41
+ """Generate random fantasy name using cached components"""
42
+ name_parts = get_name_components()
43
+ return random.choice(name_parts['prefixes']) + random.choice(name_parts['suffixes'])
44
+
45
+ def load_game_state():
46
+ """Load game state from query parameters"""
47
+ if 'player_name' in st.query_params:
48
+ st.session_state.player_name = st.query_params.player_name
 
 
 
 
49
  st.session_state.position = {
50
+ 'x': int(st.query_params.get('x', random.randint(0, GRID_WIDTH - 1))),
51
+ 'y': int(st.query_params.get('y', random.randint(0, GRID_HEIGHT - 1)))
52
  }
53
  st.session_state.character_stats = {
54
+ 'STR': int(st.query_params.get('STR', 10)),
55
+ 'DEX': int(st.query_params.get('DEX', 10)),
56
+ 'CON': int(st.query_params.get('CON', 10)),
57
+ 'INT': int(st.query_params.get('INT', 10)),
58
+ 'WIS': int(st.query_params.get('WIS', 10)),
59
+ 'CHA': int(st.query_params.get('CHA', 10)),
60
+ 'HP': int(st.query_params.get('HP', 20)),
61
+ 'MAX_HP': int(st.query_params.get('MAX_HP', 40)),
62
+ 'score': int(st.query_params.get('score', 0)),
63
+ 'created_at': float(st.query_params.get('created_at', time.time()))
64
  }
65
 
66
+ def save_game_state():
67
+ """Save game state to query parameters"""
68
  if st.session_state.player_name and st.session_state.character_stats:
69
  params = {
70
  'player_name': st.session_state.player_name,
71
+ 'x': str(st.session_state.position['x']),
72
+ 'y': str(st.session_state.position['y']),
73
+ **{k: str(v) for k, v in st.session_state.character_stats.items()}
74
  }
75
+ st.query_params.from_dict(params)
76
 
77
  # Initialize session state
78
  if 'initialized' not in st.session_state:
 
90
  }
91
  st.session_state.last_move = time.time()
92
  st.session_state.nearby_players = []
93
+ load_game_state()
94
+
95
+ @st.experimental_singleton(validate=lambda x: time.time() - x['last_update'] < 60)
96
+ def load_all_players():
97
+ """Cache and load all player states with validation"""
98
+ players = {}
99
+ if os.path.exists('players'):
100
+ for filename in os.listdir('players'):
101
+ if filename.endswith('.json'):
102
+ with open(f"players/{filename}", 'r') as f:
103
+ player_data = json.load(f)
104
+ players[player_data['name']] = player_data
105
+ return {'players': players, 'last_update': time.time()}
106
 
107
  def save_player_state():
108
  """Save player state to JSON file"""
 
117
  os.makedirs('players', exist_ok=True)
118
  with open(f"players/{st.session_state.player_name}.json", 'w') as f:
119
  json.dump(player_data, f)
120
+ save_game_state()
 
 
 
 
 
 
 
 
 
 
 
 
121
 
122
  def calculate_distance(pos1, pos2):
123
  """Calculate Manhattan distance between two positions with wrapping"""
 
138
 
139
  st.session_state.last_move = time.time()
140
  save_player_state()
 
141
 
142
  def update_nearby_players():
143
  """Update list of nearby players and calculate score gains"""
144
+ all_players = load_all_players()['players']
145
  nearby = []
146
  score_gain = 0
147
 
 
159
  if score_gain > 0:
160
  st.session_state.character_stats['score'] += score_gain
161
  save_player_state()
 
162
 
163
  st.session_state.nearby_players = nearby
164
 
165
  def create_game_board():
166
  """Create and display the game board"""
167
+ all_players = load_all_players()['players']
168
+ images = get_game_images()
 
 
 
 
169
 
170
  # Create columns for each row
171
  for y in range(GRID_HEIGHT):
 
182
 
183
  # Display appropriate image and tooltip
184
  if x == st.session_state.position['x'] and y == st.session_state.position['y']:
185
+ cols[x].image(images['player'], use_column_width=True)
186
  cols[x].markdown(f"**You** ({st.session_state.character_stats['score']} pts)")
187
  elif player_here:
188
+ cols[x].image(images['other_player'], use_column_width=True)
189
  cols[x].markdown(f"**{player_here}** ({all_players[player_here]['stats']['score']} pts)")
190
  else:
191
+ cols[x].image(images['tile'], use_column_width=True)
192
 
193
  def main():
194
  # Update nearby players on refresh
 
205
  if st.sidebar.button("Start Playing"):
206
  st.session_state.player_name = player_name
207
  if st.session_state.character_stats is None:
208
+ st.session_state.character_stats = {
209
+ 'STR': sum(sorted([random.randint(1, 6) for _ in range(4)])[1:]),
210
+ 'DEX': sum(sorted([random.randint(1, 6) for _ in range(4)])[1:]),
211
+ 'CON': sum(sorted([random.randint(1, 6) for _ in range(4)])[1:]),
212
+ 'INT': sum(sorted([random.randint(1, 6) for _ in range(4)])[1:]),
213
+ 'WIS': sum(sorted([random.randint(1, 6) for _ in range(4)])[1:]),
214
+ 'CHA': sum(sorted([random.randint(1, 6) for _ in range(4)])[1:]),
215
+ 'HP': random.randint(1, 20) * 2 + random.randint(1, 20),
216
+ 'MAX_HP': 40,
217
+ 'score': 0,
218
+ 'created_at': time.time()
219
+ }
220
  save_player_state()
 
221
  st.rerun()
222
  else:
223
  # Display nearby players
 
244
  update_position("right")
245
  st.rerun()
246
 
247
+ # Clear game state button
248
+ if st.sidebar.button("Clear Game State"):
249
+ st.query_params.clear()
250
+ st.experimental_singleton.clear()
251
+ st.rerun()
 
252
 
253
  # Main game area
254
  st.title("Multiplayer Tile Game")