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

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +133 -71
app.py CHANGED
@@ -8,11 +8,15 @@ from datetime import datetime
8
  from pathlib import Path
9
  import base64
10
  from io import BytesIO
 
 
11
 
12
  # Constants for game board
13
  GRID_WIDTH = 16
14
  GRID_HEIGHT = 9
15
  REFRESH_RATE = 5 # seconds
 
 
16
 
17
  # Fantasy name generator
18
  def generate_fantasy_name():
@@ -22,6 +26,40 @@ def generate_fantasy_name():
22
  'is', 'ax', 'on', 'ir', 'ex', 'az', 'er', 'eth', 'ys', 'ix']
23
  return random.choice(prefixes) + random.choice(suffixes)
24
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
25
  # Initialize session state
26
  if 'initialized' not in st.session_state:
27
  st.session_state.initialized = False
@@ -37,60 +75,41 @@ if 'initialized' not in st.session_state:
37
  'y': random.randint(0, GRID_HEIGHT - 1)
38
  }
39
  st.session_state.last_move = time.time()
 
 
40
 
41
- def roll_stats():
42
- return {
43
- 'STR': sum(sorted([random.randint(1, 6) for _ in range(4)])[1:]),
44
- 'DEX': sum(sorted([random.randint(1, 6) for _ in range(4)])[1:]),
45
- 'CON': sum(sorted([random.randint(1, 6) for _ in range(4)])[1:]),
46
- 'INT': sum(sorted([random.randint(1, 6) for _ in range(4)])[1:]),
47
- 'WIS': sum(sorted([random.randint(1, 6) for _ in range(4)])[1:]),
48
- 'CHA': sum(sorted([random.randint(1, 6) for _ in range(4)])[1:]),
49
- 'HP': random.randint(1, 20) * 2 + random.randint(1, 20),
50
- 'MAX_HP': 40,
51
- 'score': 0,
52
- 'created_at': time.time()
53
- }
54
-
55
- def save_character_sheet(player_name, stats):
56
- """Save character sheet as markdown"""
57
- filepath = f"characters/{player_name}.md"
58
- os.makedirs('characters', exist_ok=True)
59
-
60
- markdown = f"""# {player_name}'s Character Sheet
61
-
62
- ## Stats
63
- - **STR**: {stats['STR']}
64
- - **DEX**: {stats['DEX']}
65
- - **CON**: {stats['CON']}
66
- - **INT**: {stats['INT']}
67
- - **WIS**: {stats['WIS']}
68
- - **CHA**: {stats['CHA']}
69
-
70
- ## Health
71
- HP: {stats['HP']}/{stats['MAX_HP']}
72
-
73
- ## Score
74
- Current Score: {stats['score']}
75
 
76
- ## Position
77
- X: {st.session_state.position['x']}, Y: {st.session_state.position['y']}
 
 
 
 
 
 
 
 
 
 
78
 
79
- ## Session Info
80
- Created: {datetime.fromtimestamp(stats['created_at']).strftime('%Y-%m-%d %H:%M:%S')}
81
- Last Updated: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
82
- """
83
-
84
- with open(filepath, 'w') as f:
85
- f.write(markdown)
86
-
87
- def load_character_sheet(player_name):
88
- """Load character sheet if it exists"""
89
- filepath = f"characters/{player_name}.md"
90
- if os.path.exists(filepath):
91
- with open(filepath, 'r') as f:
92
- return f.read()
93
- return None
94
 
95
  def update_position(direction):
96
  """Update player position with wrapping"""
@@ -104,27 +123,69 @@ def update_position(direction):
104
  st.session_state.position['x'] = (st.session_state.position['x'] + 1) % GRID_WIDTH
105
 
106
  st.session_state.last_move = time.time()
107
- if st.session_state.character_stats:
108
- save_character_sheet(st.session_state.player_name, st.session_state.character_stats)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
109
 
110
  def create_game_board():
111
  """Create and display the game board"""
 
 
112
  # Create placeholder images for tiles
113
  tile_image = Image.new('RGB', (50, 50), color='green')
114
  player_image = Image.new('RGB', (50, 50), color='blue')
 
115
 
116
  # Create columns for each row
117
  for y in range(GRID_HEIGHT):
118
  cols = st.columns(GRID_WIDTH)
119
  for x in range(GRID_WIDTH):
120
- # Display player or tile
121
- if (x == st.session_state.position['x'] and
122
- y == st.session_state.position['y']):
 
 
 
 
 
 
 
 
123
  cols[x].image(player_image, use_column_width=True)
 
 
 
 
124
  else:
125
  cols[x].image(tile_image, use_column_width=True)
126
 
127
  def main():
 
 
 
128
  # Sidebar for player info and controls
129
  st.sidebar.title("Player Info")
130
 
@@ -137,23 +198,16 @@ def main():
137
  st.session_state.player_name = player_name
138
  if st.session_state.character_stats is None:
139
  st.session_state.character_stats = roll_stats()
140
- save_character_sheet(player_name, st.session_state.character_stats)
 
141
  st.rerun()
142
  else:
143
- # Show current name and allow changes
144
- new_name = st.sidebar.text_input("Your name:",
145
- value=st.session_state.player_name)
146
- if new_name != st.session_state.player_name:
147
- old_name = st.session_state.player_name
148
- st.session_state.player_name = new_name
149
- os.rename(f"characters/{old_name}.md",
150
- f"characters/{new_name}.md")
151
- st.rerun()
152
-
153
- # Display character sheet
154
- character_sheet = load_character_sheet(st.session_state.player_name)
155
- if character_sheet:
156
- st.sidebar.markdown(character_sheet)
157
 
158
  # Movement controls
159
  st.sidebar.markdown("### Movement Controls")
@@ -171,6 +225,13 @@ def main():
171
  if cols[2].button("➡️", key="right"):
172
  update_position("right")
173
  st.rerun()
 
 
 
 
 
 
 
174
 
175
  # Main game area
176
  st.title("Multiplayer Tile Game")
@@ -181,6 +242,7 @@ def main():
181
  # Auto-refresh logic
182
  if (time.time() - st.session_state.last_move) > REFRESH_RATE:
183
  st.session_state.last_move = time.time()
 
184
  st.rerun()
185
 
186
  if __name__ == "__main__":
 
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():
 
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:
65
  st.session_state.initialized = False
 
75
  'y': random.randint(0, GRID_HEIGHT - 1)
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"""
83
+ if st.session_state.player_name:
84
+ player_data = {
85
+ 'name': st.session_state.player_name,
86
+ 'position': st.session_state.position,
87
+ 'stats': st.session_state.character_stats,
88
+ 'last_update': time.time()
89
+ }
90
+
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"""
110
+ dx = min(abs(pos1['x'] - pos2['x']), GRID_WIDTH - abs(pos1['x'] - pos2['x']))
111
+ dy = min(abs(pos1['y'] - pos2['y']), GRID_HEIGHT - abs(pos1['y'] - pos2['y']))
112
+ return dx + dy
 
 
 
 
 
 
 
 
 
 
113
 
114
  def update_position(direction):
115
  """Update player position with wrapping"""
 
123
  st.session_state.position['x'] = (st.session_state.position['x'] + 1) % GRID_WIDTH
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
+
135
+ for player_name, player_data in all_players.items():
136
+ if player_name != st.session_state.player_name:
137
+ distance = calculate_distance(st.session_state.position, player_data['position'])
138
+ if distance <= INTERACTION_RADIUS:
139
+ nearby.append({
140
+ 'name': player_name,
141
+ 'distance': distance,
142
+ 'score': player_data['stats']['score']
143
+ })
144
+ score_gain += POINTS_PER_INTERACTION
145
+
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):
164
  cols = st.columns(GRID_WIDTH)
165
  for x in range(GRID_WIDTH):
166
+ current_pos = {'x': x, 'y': y}
167
+
168
+ # Check if any player is on this tile
169
+ player_here = None
170
+ for player_name, player_data in all_players.items():
171
+ if (player_data['position']['x'] == x and
172
+ player_data['position']['y'] == y):
173
+ player_here = player_name
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
187
+ update_nearby_players()
188
+
189
  # Sidebar for player info and controls
190
  st.sidebar.title("Player Info")
191
 
 
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
206
+ st.sidebar.markdown("### Nearby Players")
207
+ for player in st.session_state.nearby_players:
208
+ st.sidebar.markdown(
209
+ f"**{player['name']}** - {player['distance']} tiles away - {player['score']} pts"
210
+ )
 
 
 
 
 
 
 
 
211
 
212
  # Movement controls
213
  st.sidebar.markdown("### Movement Controls")
 
225
  if cols[2].button("➡️", key="right"):
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")
 
242
  # Auto-refresh logic
243
  if (time.time() - st.session_state.last_move) > REFRESH_RATE:
244
  st.session_state.last_move = time.time()
245
+ save_player_state()
246
  st.rerun()
247
 
248
  if __name__ == "__main__":