awacke1 commited on
Commit
c0ad2f5
Β·
verified Β·
1 Parent(s): e6709a9

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +250 -0
app.py ADDED
@@ -0,0 +1,250 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import streamlit.components.v1 as components
3
+ import os
4
+ import random
5
+ import time
6
+ from PIL import Image
7
+ import json
8
+ from datetime import datetime
9
+ from pathlib import Path
10
+ import base64
11
+ from io import BytesIO
12
+
13
+ # Initialize session state variables
14
+ if 'game_state' not in st.session_state:
15
+ st.session_state.game_state = {
16
+ 'players': {},
17
+ 'chat_messages': [],
18
+ 'tile_map': [],
19
+ 'current_player': None
20
+ }
21
+
22
+ if 'player_name' not in st.session_state:
23
+ st.session_state.player_name = None
24
+
25
+ if 'last_refresh' not in st.session_state:
26
+ st.session_state.last_refresh = time.time()
27
+
28
+ if 'start_time' not in st.session_state:
29
+ st.session_state.start_time = None
30
+
31
+ if 'play_duration' not in st.session_state:
32
+ st.session_state.play_duration = 0
33
+
34
+ # Utility functions
35
+ def load_tiles_and_text():
36
+ """Load tile images and their corresponding markdown text from the root directory"""
37
+ tiles = {}
38
+ for file in os.listdir('.'):
39
+ if file.endswith(('.png', '.jpg', '.jpeg')):
40
+ tile_name = os.path.splitext(file)[0]
41
+ # Load image
42
+ img = Image.open(file)
43
+ # Convert image to base64 for HTML embedding
44
+ buffered = BytesIO()
45
+ img.save(buffered, format="PNG")
46
+ img_str = base64.b64encode(buffered.getvalue()).decode()
47
+
48
+ # Check for corresponding markdown file
49
+ md_file = f"{tile_name}.md"
50
+ overlay_text = ""
51
+ if os.path.exists(md_file):
52
+ with open(md_file, 'r') as f:
53
+ overlay_text = f.read().strip()
54
+
55
+ tiles[tile_name] = {
56
+ 'image': img_str,
57
+ 'text': overlay_text
58
+ }
59
+ return tiles
60
+
61
+ def generate_map(width=20, height=15):
62
+ """Generate a random tile map"""
63
+ tile_types = ['grass', 'water', 'rock']
64
+ return [[random.choice(tile_types) for _ in range(width)] for _ in range(height)]
65
+
66
+ def create_tile_html(tile_data, size=60):
67
+ """Create HTML for a single tile with text overlay"""
68
+ return f"""
69
+ <div style="position: relative; width: {size}px; height: {size}px; display: inline-block;">
70
+ <img src="data:image/png;base64,{tile_data['image']}"
71
+ style="width: {size}px; height: {size}px; object-fit: cover;">
72
+ <div style="position: absolute; top: 0; left: 0; right: 0; bottom: 0;
73
+ background-color: rgba(255, 255, 255, 0.7);
74
+ display: flex; align-items: center; justify-content: center;
75
+ text-align: center; font-size: 10px; padding: 2px;
76
+ opacity: 0.8; pointer-events: none;">
77
+ {tile_data['text']}
78
+ </div>
79
+ </div>
80
+ """
81
+
82
+ def create_game_board_html(tile_map, tiles, players):
83
+ """Create HTML for the entire game board"""
84
+ board_html = """
85
+ <style>
86
+ .game-board { line-height: 0; }
87
+ .player-marker {
88
+ position: absolute;
89
+ width: 10px;
90
+ height: 10px;
91
+ background-color: red;
92
+ border-radius: 50%;
93
+ z-index: 2;
94
+ }
95
+ </style>
96
+ <div class="game-board">
97
+ """
98
+
99
+ for y, row in enumerate(tile_map):
100
+ for x, tile_type in enumerate(row):
101
+ if tile_type in tiles:
102
+ board_html += create_tile_html(tiles[tile_type])
103
+ board_html += "<br>"
104
+
105
+ # Add player markers
106
+ for player_name, player_data in players.items():
107
+ pos_x = player_data['position']['x'] * 60 + 25
108
+ pos_y = player_data['position']['y'] * 60 + 25
109
+ board_html += f"""
110
+ <div class="player-marker" style="left: {pos_x}px; top: {pos_y}px;"
111
+ title="{player_name}"></div>
112
+ """
113
+
114
+ board_html += "</div>"
115
+ return board_html
116
+
117
+ def save_game_state():
118
+ """Save the current game state to a file"""
119
+ state_file = Path("game_state.json")
120
+ state_to_save = {
121
+ 'players': st.session_state.game_state['players'],
122
+ 'chat_messages': st.session_state.game_state['chat_messages'],
123
+ 'tile_map': st.session_state.game_state['tile_map']
124
+ }
125
+ with open(state_file, 'w') as f:
126
+ json.dump(state_to_save, f)
127
+
128
+ def load_game_state():
129
+ """Load the game state from file"""
130
+ state_file = Path("game_state.json")
131
+ if state_file.exists():
132
+ with open(state_file, 'r') as f:
133
+ loaded_state = json.load(f)
134
+ st.session_state.game_state.update(loaded_state)
135
+
136
+ def add_chat_message(player_name, message):
137
+ """Add a message to the chat history"""
138
+ timestamp = datetime.now().strftime("%H:%M:%S")
139
+ st.session_state.game_state['chat_messages'].append({
140
+ 'player': player_name,
141
+ 'message': message,
142
+ 'timestamp': timestamp
143
+ })
144
+ save_game_state()
145
+
146
+ def format_duration(seconds):
147
+ """Format duration in seconds to HH:MM:SS"""
148
+ hours = seconds // 3600
149
+ minutes = (seconds % 3600) // 60
150
+ seconds = seconds % 60
151
+ return f"{int(hours):02d}:{int(minutes):02d}:{int(seconds):02d}"
152
+
153
+ def check_auto_refresh():
154
+ """Check if it's time to refresh the page"""
155
+ current_time = time.time()
156
+ if current_time - st.session_state.last_refresh >= 5:
157
+ st.session_state.last_refresh = current_time
158
+ st.rerun()
159
+
160
+ def update_play_duration():
161
+ """Update the player's total play duration"""
162
+ if st.session_state.start_time is not None:
163
+ current_time = time.time()
164
+ st.session_state.play_duration = int(current_time - st.session_state.start_time)
165
+
166
+ # Main game UI
167
+ def main():
168
+ st.title("Multiplayer Tile Game")
169
+
170
+ if st.session_state.player_name is None:
171
+ with st.form("join_game"):
172
+ player_name = st.text_input("Enter your name:")
173
+ submitted = st.form_submit_button("Join Game")
174
+ if submitted and player_name:
175
+ st.session_state.player_name = player_name
176
+ st.session_state.start_time = time.time()
177
+ st.session_state.play_duration = 0
178
+ st.session_state.game_state['players'][player_name] = {
179
+ 'position': {'x': 0, 'y': 0},
180
+ 'last_active': time.time(),
181
+ 'score': 0
182
+ }
183
+ st.rerun()
184
+
185
+ else:
186
+ update_play_duration()
187
+ st.sidebar.metric("Play Time", format_duration(st.session_state.play_duration))
188
+
189
+ col1, col2 = st.columns([2, 1])
190
+
191
+ with col1:
192
+ st.subheader("Game Map")
193
+ if not st.session_state.game_state['tile_map']:
194
+ st.session_state.game_state['tile_map'] = generate_map()
195
+
196
+ tiles = load_tiles_and_text()
197
+ if tiles:
198
+ # Generate and display the game board
199
+ board_html = create_game_board_html(
200
+ st.session_state.game_state['tile_map'],
201
+ tiles,
202
+ st.session_state.game_state['players']
203
+ )
204
+ components.html(board_html, height=600)
205
+
206
+ # Movement controls
207
+ if st.session_state.player_name:
208
+ player = st.session_state.game_state['players'][st.session_state.player_name]
209
+
210
+ cols = st.columns(4)
211
+ if cols[0].button("←"):
212
+ player['position']['x'] = max(0, player['position']['x'] - 1)
213
+ if cols[1].button("↑"):
214
+ player['position']['y'] = max(0, player['position']['y'] - 1)
215
+ if cols[2].button("↓"):
216
+ player['position']['y'] = min(14, player['position']['y'] + 1)
217
+ if cols[3].button("β†’"):
218
+ player['position']['x'] = min(19, player['position']['x'] + 1)
219
+
220
+ st.write(f"Position: ({player['position']['x']}, {player['position']['y']})")
221
+ else:
222
+ st.warning("No image files found. Please add .png files and optional .md files with matching names.")
223
+
224
+ with col2:
225
+ st.subheader("Chat Room")
226
+ chat_container = st.container()
227
+ with chat_container:
228
+ for message in st.session_state.game_state['chat_messages'][-50:]:
229
+ st.text(f"[{message['timestamp']}] {message['player']}: {message['message']}")
230
+
231
+ with st.form("chat_form", clear_on_submit=True):
232
+ message = st.text_input("Message:")
233
+ if st.form_submit_button("Send") and message:
234
+ add_chat_message(st.session_state.player_name, message)
235
+ st.rerun()
236
+
237
+ if st.button("Leave Game"):
238
+ if st.session_state.player_name in st.session_state.game_state['players']:
239
+ del st.session_state.game_state['players'][st.session_state.player_name]
240
+ st.session_state.player_name = None
241
+ st.session_state.start_time = None
242
+ st.session_state.play_duration = 0
243
+ save_game_state()
244
+ st.rerun()
245
+
246
+ check_auto_refresh()
247
+
248
+ if __name__ == "__main__":
249
+ load_game_state()
250
+ main()