Taf2023 commited on
Commit
a8c7059
·
verified ·
1 Parent(s): 4e81ce1

Deploy Gradio app with multiple files

Browse files
Files changed (4) hide show
  1. app.py +369 -0
  2. models.py +214 -0
  3. requirements.txt +3 -0
  4. utils.py +322 -0
app.py ADDED
@@ -0,0 +1,369 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import json
3
+ import random
4
+ import time
5
+ from datetime import datetime
6
+ import pandas as pd
7
+ from utils import (
8
+ initialize_game_state,
9
+ create_box,
10
+ calculate_battle_result,
11
+ get_shop_items,
12
+ purchase_item,
13
+ get_leaderboard,
14
+ save_game_state,
15
+ load_game_state
16
+ )
17
+ from models import Box, Battle, Shop
18
+
19
+ # Global game state
20
+ game_state = {}
21
+
22
+ def authenticate_user(profile):
23
+ """Handle user authentication"""
24
+ if profile is None:
25
+ return None, "❌ Please login to play", gr.update(visible=False)
26
+
27
+ user_id = profile["name"]
28
+ if user_id not in game_state:
29
+ game_state[user_id] = initialize_game_state(user_id)
30
+
31
+ return user_id, f"✅ Welcome back, {user_id}!", gr.update(visible=True)
32
+
33
+ def create_user_box(user_id, box_name):
34
+ """Create a new box for the user"""
35
+ if not box_name.strip():
36
+ return "❌ Please enter a box name", get_user_status(user_id)
37
+
38
+ box = create_box(box_name.strip())
39
+ game_state[user_id]["box"] = box
40
+ game_state[user_id]["coins"] = 100 # Starting coins
41
+
42
+ status = get_user_status(user_id)
43
+ return f"✅ Box '{box_name}' created successfully! Starting with 100 coins.", status
44
+
45
+ def get_user_status(user_id):
46
+ """Get current user status as formatted text"""
47
+ if user_id not in game_state:
48
+ return "❌ User not found"
49
+
50
+ user_data = game_state[user_id]
51
+ box = user_data.get("box")
52
+
53
+ if not box:
54
+ return "❌ No box created yet"
55
+
56
+ status = f"""
57
+ 📦 BOX STATUS: {box.name}
58
+ ⚔️ Attack: {box.attack}
59
+ 🛡️ Defense: {box.defense}
60
+ ❤️ Health: {box.health}/{box.max_health}
61
+ ⚡ Speed: {box.speed}
62
+ 🪙 Coins: {user_data.get('coins', 0)}
63
+ 🏆 Wins: {user_data.get('wins', 0)}
64
+ 💀 Losses: {user_data.get('losses', 0)}
65
+ 📊 Level: {box.level}
66
+ ✨ XP: {box.xp}/{box.xp_to_next_level}
67
+ """
68
+ return status.strip()
69
+
70
+ def battle_opponent(user_id, opponent_type="system"):
71
+ """Battle against an opponent"""
72
+ if user_id not in game_state or not game_state[user_id].get("box"):
73
+ return "❌ Create a box first!", get_user_status(user_id)
74
+
75
+ user_box = game_state[user_id]["box"]
76
+
77
+ if opponent_type == "system":
78
+ # Create system box with level based on user level
79
+ system_level = max(1, user_box.level + random.randint(-2, 2))
80
+ opponent = create_box(f"System Bot Lv.{system_level}")
81
+ opponent.level = system_level
82
+ opponent.attack = 10 + system_level * 5
83
+ opponent.defense = 8 + system_level * 4
84
+ opponent.health = 50 + system_level * 20
85
+ opponent.max_health = opponent.health
86
+ opponent.speed = 5 + system_level * 2
87
+ else:
88
+ # For multiplayer - create a random opponent for demo
89
+ opponent = create_box(f"Player Box")
90
+ opponent.level = random.randint(1, 10)
91
+ opponent.attack = 15 + opponent.level * 3
92
+ opponent.defense = 12 + opponent.level * 2
93
+ opponent.health = 40 + opponent.level * 15
94
+ opponent.max_health = opponent.health
95
+ opponent.speed = 3 + opponent.level
96
+
97
+ battle_result = calculate_battle_result(user_box, opponent)
98
+
99
+ # Update user stats
100
+ if battle_result["winner"] == "user":
101
+ game_state[user_id]["wins"] = game_state[user_id].get("wins", 0) + 1
102
+ coins_earned = 20 + opponent.level * 5
103
+ game_state[user_id]["coins"] = game_state[user_id].get("coins", 0) + coins_earned
104
+ user_box.gain_xp(10 + opponent.level * 5)
105
+ result_text = f"""
106
+ 🎉 VICTORY!
107
+ 🏆 You defeated {opponent.name}!
108
+ 🪙 Earned {coins_earned} coins
109
+ ✨ Gained {10 + opponent.level * 5} XP
110
+ """
111
+ else:
112
+ game_state[user_id]["losses"] = game_state[user_id].get("losses", 0) + 1
113
+ coins_earned = 5
114
+ game_state[user_id]["coins"] = game_state[user_id].get("coins", 0) + coins_earned
115
+ result_text = f"""
116
+ 💀 DEFEAT!
117
+ 😔 You were defeated by {opponent.name}
118
+ 🪙 Earned {coins_earned} coins (consolation prize)
119
+ """
120
+
121
+ battle_log = f"""
122
+ ⚔️ BATTLE LOG
123
+ {battle_result["log"]}
124
+ """
125
+
126
+ return result_text.strip(), battle_log.strip(), get_user_status(user_id)
127
+
128
+ def show_shop(user_id):
129
+ """Display shop items"""
130
+ if user_id not in game_state:
131
+ return "❌ Please login first", ""
132
+
133
+ user_coins = game_state[user_id].get("coins", 0)
134
+ items = get_shop_items()
135
+
136
+ shop_text = f"🪙 Your Coins: {user_coins}\n\n🛍️ SHOP ITEMS:\n\n"
137
+
138
+ for i, item in enumerate(items, 1):
139
+ affordable = "✅" if user_coins >= item["cost"] else "❌"
140
+ shop_text += f"{i}. {item['name']} - {item['cost']} coins {affordable}\n"
141
+ shop_text += f" {item['description']}\n"
142
+ shop_text += f" Effect: {item['effect']}\n\n"
143
+
144
+ return shop_text, ""
145
+
146
+ def buy_item(user_id, item_choice):
147
+ """Purchase an item from the shop"""
148
+ if user_id not in game_state:
149
+ return "❌ Please login first", show_shop(user_id)
150
+
151
+ try:
152
+ item_num = int(item_choice)
153
+ items = get_shop_items()
154
+
155
+ if item_num < 1 or item_num > len(items):
156
+ return "❌ Invalid item number", show_shop(user_id)
157
+
158
+ item = items[item_num - 1]
159
+ result = purchase_item(game_state[user_id], item)
160
+
161
+ if result["success"]:
162
+ return f"✅ {result['message']}", show_shop(user_id)
163
+ else:
164
+ return f"❌ {result['message']}", show_shop(user_id)
165
+
166
+ except ValueError:
167
+ return "❌ Please enter a valid number", show_shop(user_id)
168
+
169
+ def show_leaderboard():
170
+ """Display the global leaderboard"""
171
+ leaderboard = get_leaderboard(game_state)
172
+
173
+ if not leaderboard:
174
+ return "🏆 LEADERBOARD\n\nNo players yet. Be the first!"
175
+
176
+ board_text = "🏆 GLOBAL LEADERBOARD\n\n"
177
+
178
+ for i, player in enumerate(leaderboard[:10], 1):
179
+ medal = "🥇" if i == 1 else "🥈" if i == 2 else "🥉" if i == 3 else "🏅"
180
+ win_rate = (player['wins'] / (player['wins'] + player['losses']) * 100) if (player['wins'] + player['losses']) > 0 else 0
181
+ board_text += f"{medal} {i}. {player['name']}\n"
182
+ board_text += f" 🏆 Wins: {player['wins']} | 💀 Losses: {player['losses']}\n"
183
+ board_text += f" 📊 Win Rate: {win_rate:.1f}% | 📦 Box: {player['box_name']}\n\n"
184
+
185
+ return board_text
186
+
187
+ def auto_upgrade_system_boxes():
188
+ """Automatically upgrade system boxes"""
189
+ while True:
190
+ time.sleep(30) # Every 30 seconds
191
+ # System boxes upgrade logic would go here
192
+ # For now, this is a placeholder
193
+
194
+ def create_interface():
195
+ """Create the main game interface"""
196
+
197
+ with gr.Blocks(
198
+ title="Box Battle Arena - Accessible Fighting Game",
199
+ css="""
200
+ .accessibility-mode {
201
+ font-size: 18px;
202
+ line-height: 1.6;
203
+ }
204
+ .game-status {
205
+ background-color: #f0f0f0;
206
+ padding: 15px;
207
+ border-radius: 10px;
208
+ font-family: monospace;
209
+ }
210
+ """,
211
+ theme=gr.themes.Soft()
212
+ ) as demo:
213
+
214
+ # Header with accessibility info
215
+ gr.HTML("""
216
+ <div style="text-align: center; margin-bottom: 20px;">
217
+ <h1>🥊 Box Battle Arena 🥊</h1>
218
+ <p><a href="https://huggingface.co/spaces/akhaliq/anycoder" target="_blank">Built with anycoder</a></p>
219
+ <p>🔊 This game is fully accessible for screen reader users</p>
220
+ <p>Use Tab to navigate, Enter to select, and screen reader will announce all actions</p>
221
+ </div>
222
+ """)
223
+
224
+ # Login section
225
+ with gr.Row():
226
+ with gr.Column(scale=1):
227
+ login_btn = gr.LoginButton()
228
+ user_info = gr.HTML("<p>🔐 Please login with Hugging Face to play</p>")
229
+
230
+ # Main game area (hidden until login)
231
+ with gr.Group(visible=False) as game_area:
232
+ # Box Creation
233
+ with gr.Group():
234
+ gr.Markdown("## 📦 Create Your Box")
235
+ with gr.Row():
236
+ box_name_input = gr.Textbox(
237
+ label="Box Name",
238
+ placeholder="Enter your box name...",
239
+ elem_id="box_name_input"
240
+ )
241
+ create_box_btn = gr.Button("Create Box", variant="primary")
242
+
243
+ create_result = gr.Textbox(label="Creation Result", interactive=False)
244
+
245
+ # Status Display
246
+ with gr.Group():
247
+ gr.Markdown("## 📊 Your Status")
248
+ user_status = gr.Textbox(
249
+ label="Current Status",
250
+ value="No box created yet",
251
+ interactive=False,
252
+ elem_classes=["game-status"]
253
+ )
254
+
255
+ # Battle Section
256
+ with gr.Group():
257
+ gr.Markdown("## ⚔️ Battle Arena")
258
+ with gr.Row():
259
+ battle_system_btn = gr.Button("🤖 Battle System Box", variant="primary")
260
+ battle_player_btn = gr.Button("👥 Battle Player Box", variant="secondary")
261
+
262
+ battle_result = gr.Textbox(label="Battle Result", interactive=False)
263
+ battle_log = gr.Textbox(
264
+ label="Battle Log",
265
+ lines=10,
266
+ interactive=False,
267
+ elem_classes=["game-status"]
268
+ )
269
+
270
+ # Shop Section
271
+ with gr.Group():
272
+ gr.Markdown("## 🛍️ Shop")
273
+ with gr.Row():
274
+ shop_btn = gr.Button("View Shop")
275
+ refresh_shop_btn = gr.Button("🔄 Refresh")
276
+
277
+ shop_display = gr.Textbox(
278
+ label="Shop Items",
279
+ lines=15,
280
+ interactive=False,
281
+ elem_classes=["game-status"]
282
+ )
283
+
284
+ with gr.Row():
285
+ item_choice_input = gr.Number(
286
+ label="Item Number",
287
+ minimum=1,
288
+ maximum=10,
289
+ step=1
290
+ )
291
+ buy_btn = gr.Button("Buy Item", variant="primary")
292
+
293
+ shop_result = gr.Textbox(label="Purchase Result", interactive=False)
294
+
295
+ # Leaderboard
296
+ with gr.Group():
297
+ gr.Markdown("## 🏆 Leaderboard")
298
+ leaderboard_btn = gr.Button("View Leaderboard")
299
+ leaderboard_display = gr.Textbox(
300
+ label="Top Players",
301
+ lines=15,
302
+ interactive=False,
303
+ elem_classes=["game-status"]
304
+ )
305
+
306
+ # Event handlers
307
+ def handle_login(profile):
308
+ if profile:
309
+ user_id, msg, visibility = authenticate_user(profile)
310
+ return (
311
+ gr.update(value=f"✅ Logged in as: {profile['name']}"),
312
+ gr.update(visible=True),
313
+ user_status.update(value=get_user_status(user_id) if user_id else "No box created yet")
314
+ )
315
+ return gr.update(), gr.update(visible=False), gr.update()
316
+
317
+ login_btn.click(
318
+ handle_login,
319
+ inputs=[],
320
+ outputs=[user_info, game_area, user_status]
321
+ )
322
+
323
+ create_box_btn.click(
324
+ create_user_box,
325
+ inputs=[gr.Textbox()], # Will be replaced with actual user_id tracking
326
+ outputs=[create_result, user_status]
327
+ )
328
+
329
+ battle_system_btn.click(
330
+ lambda: battle_opponent("demo_user"), # Demo user
331
+ outputs=[battle_result, battle_log, user_status]
332
+ )
333
+
334
+ battle_player_btn.click(
335
+ lambda: battle_opponent("demo_user", "player"), # Demo user
336
+ outputs=[battle_result, battle_log, user_status]
337
+ )
338
+
339
+ shop_btn.click(
340
+ lambda: show_shop("demo_user"), # Demo user
341
+ outputs=[shop_display, shop_result]
342
+ )
343
+
344
+ buy_btn.click(
345
+ lambda x: buy_item("demo_user", x), # Demo user
346
+ inputs=[item_choice_input],
347
+ outputs=[shop_result, shop_display]
348
+ )
349
+
350
+ leaderboard_btn.click(
351
+ show_leaderboard,
352
+ outputs=[leaderboard_display]
353
+ )
354
+
355
+ refresh_shop_btn.click(
356
+ lambda: show_shop("demo_user"), # Demo user
357
+ outputs=[shop_display, shop_result]
358
+ )
359
+
360
+ return demo
361
+
362
+ if __name__ == "__main__":
363
+ demo = create_interface()
364
+ demo.launch(
365
+ server_name="0.0.0.0",
366
+ server_port=7860,
367
+ share=True,
368
+ show_api=False
369
+ )
models.py ADDED
@@ -0,0 +1,214 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import random
2
+
3
+ class Box:
4
+ """Box character class"""
5
+
6
+ def __init__(self, name="Unnamed Box"):
7
+ self.name = name
8
+ self.attack = 10
9
+ self.defense = 8
10
+ self.health = 50
11
+ self.max_health = 50
12
+ self.speed = 5
13
+ self.level = 1
14
+ self.xp = 0
15
+ self.xp_to_next_level = 100
16
+ self.ability = None
17
+
18
+ def gain_xp(self, amount):
19
+ """Add XP and check for level up"""
20
+ self.xp += amount
21
+
22
+ while self.xp >= self.xp_to_next_level:
23
+ self.level_up()
24
+
25
+ def level_up(self):
26
+ """Level up the box"""
27
+ self.level += 1
28
+ self.xp -= self.xp_to_next_level
29
+ self.xp_to_next_level = int(self.xp_to_next_level * 1.5)
30
+
31
+ # Increase stats
32
+ self.attack += 2
33
+ self.defense += 2
34
+ self.max_health += 10
35
+ self.health = self.max_health # Full heal on level up
36
+ self.speed += 1
37
+
38
+ # Upgrade ability
39
+ if self.ability and "level" in self.ability:
40
+ self.ability["level"] += 1
41
+
42
+ def heal(self, amount):
43
+ """Heal the box"""
44
+ self.health = min(self.max_health, self.health + amount)
45
+
46
+ def take_damage(self, damage):
47
+ """Apply damage to the box"""
48
+ self.health = max(0, self.health - damage)
49
+
50
+ def is_alive(self):
51
+ """Check if box is alive"""
52
+ return self.health > 0
53
+
54
+ def get_status_string(self):
55
+ """Get formatted status string"""
56
+ return f"""
57
+ 📦 {self.name} (Level {self.level})
58
+ ⚔️ Attack: {self.attack}
59
+ 🛡️ Defense: {self.defense}
60
+ ❤️ Health: {self.health}/{self.max_health}
61
+ ⚡ Speed: {self.speed}
62
+ ✨ XP: {self.xp}/{self.xp_to_next_level}
63
+ 🎯 Ability: {self.ability['name'] if self.ability else 'None'}
64
+ """.strip()
65
+
66
+ class Battle:
67
+ """Battle class for managing fights"""
68
+
69
+ def __init__(self, attacker, defender):
70
+ self.attacker = attacker
71
+ self.defender = defender
72
+ self.rounds = 0
73
+ self.battle_log = []
74
+ self.winner = None
75
+
76
+ def start_battle(self):
77
+ """Start the battle"""
78
+ self.rounds = 0
79
+ self.battle_log = []
80
+
81
+ # Determine who goes first
82
+ attacker_first = self.attacker.speed >= self.defender.speed
83
+
84
+ self.battle_log.append(f"⚔️ Battle Start: {self.attacker.name} vs {self.defender.name}!")
85
+ self.battle_log.append(f"{self.attacker.name} goes first!" if attacker_first else f"{self.defender.name} goes first!")
86
+
87
+ max_rounds = 20
88
+
89
+ while self.attacker.is_alive() and self.defender.is_alive() and self.rounds < max_rounds:
90
+ self.rounds += 1
91
+ self.battle_log.append(f"\n--- Round {self.rounds} ---")
92
+
93
+ if attacker_first:
94
+ self.execute_round(self.attacker, self.defender)
95
+ if self.defender.is_alive():
96
+ self.execute_round(self.defender, self.attacker)
97
+ else:
98
+ self.execute_round(self.defender, self.attacker)
99
+ if self.attacker.is_alive():
100
+ self.execute_round(self.attacker, self.defender)
101
+
102
+ # Determine winner
103
+ if self.attacker.is_alive() and not self.defender.is_alive():
104
+ self.winner = self.attacker
105
+ self.battle_log.append(f"\n🎉 {self.attacker.name} WINS!")
106
+ elif self.defender.is_alive() and not self.attacker.is_alive():
107
+ self.winner = self.defender
108
+ self.battle_log.append(f"\n💀 {self.defender.name} WINS!")
109
+ else:
110
+ # Draw or max rounds
111
+ if self.attacker.health > self.defender.health:
112
+ self.winner = self.attacker
113
+ self.battle_log.append(f"\n⏰ Time's up! {self.attacker.name} wins by health!")
114
+ elif self.defender.health > self.attacker.health:
115
+ self.winner = self.defender
116
+ self.battle_log.append(f"\n⏰ Time's up! {self.defender.name} wins by health!")
117
+ else:
118
+ self.winner = None
119
+ self.battle_log.append(f"\n🤝 It's a DRAW!")
120
+
121
+ return {
122
+ "winner": self.winner,
123
+ "rounds": self.rounds,
124
+ "log": "\n".join(self.battle_log)
125
+ }
126
+
127
+ def execute_round(self, attacker, defender):
128
+ """Execute a single round"""
129
+ damage = max(1, attacker.attack - defender.defense + random.randint(-2, 3))
130
+
131
+ # Apply ability effects
132
+ if attacker.ability:
133
+ if "damage_bonus" in attacker.ability:
134
+ damage += attacker.ability["damage_bonus"]
135
+ self.battle_log.append(f"{attacker.name} uses {attacker.ability['name']}!")
136
+
137
+ if "crit_chance" in attacker.ability and random.random() < attacker.ability["crit_chance"]:
138
+ damage *= 2
139
+ self.battle_log.append(f"💥 CRITICAL HIT!")
140
+
141
+ defender.take_damage(damage)
142
+ self.battle_log.append(f"{attacker.name} deals {damage} damage to {defender.name}")
143
+ self.battle_log.append(f"{defender.name} health: {defender.health}/{defender.max_health}")
144
+
145
+ class Shop:
146
+ """Shop class for managing items"""
147
+
148
+ def __init__(self):
149
+ self.items = self.generate_shop_items()
150
+
151
+ def generate_shop_items(self):
152
+ """Generate shop items"""
153
+ return [
154
+ {
155
+ "id": 1,
156
+ "name": "Power Boost",
157
+ "cost": 50,
158
+ "description": "Increase attack by 3",
159
+ "type": "stat_boost",
160
+ "stat": "attack",
161
+ "value": 3
162
+ },
163
+ {
164
+ "id": 2,
165
+ "name": "Defense Shield",
166
+ "cost": 40,
167
+ "description": "Increase defense by 3",
168
+ "type": "stat_boost",
169
+ "stat": "defense",
170
+ "value": 3
171
+ },
172
+ {
173
+ "id": 3,
174
+ "name": "Health Potion",
175
+ "cost": 30,
176
+ "description": "Restore 20 health",
177
+ "type": "heal",
178
+ "value": 20
179
+ },
180
+ {
181
+ "id": 4,
182
+ "name": "Speed Boots",
183
+ "cost": 60,
184
+ "description": "Increase speed by 2",
185
+ "type": "stat_boost",
186
+ "stat": "speed",
187
+ "value": 2
188
+ },
189
+ {
190
+ "id": 5,
191
+ "name": "Mystery Box",
192
+ "cost": 100,
193
+ "description": "Random stat boost",
194
+ "type": "random"
195
+ }
196
+ ]
197
+
198
+ def get_item(self, item_id):
199
+ """Get item by ID"""
200
+ for item in self.items:
201
+ if item["id"] == item_id:
202
+ return item
203
+ return None
204
+
205
+ def purchase_item(self, user_coins, item_id):
206
+ """Purchase an item"""
207
+ item = self.get_item(item_id)
208
+ if not item:
209
+ return {"success": False, "message": "Item not found"}
210
+
211
+ if user_coins < item["cost"]:
212
+ return {"success": False, "message": "Not enough coins"}
213
+
214
+ return {"success": True, "item": item, "message": f"Purchased {item['name']}"}
requirements.txt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ gradio[mcp]
2
+ pandas
3
+ numpy
utils.py ADDED
@@ -0,0 +1,322 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import random
2
+ import json
3
+ from datetime import datetime
4
+ from models import Box
5
+
6
+ def initialize_game_state(user_id):
7
+ """Initialize game state for a new user"""
8
+ return {
9
+ "user_id": user_id,
10
+ "box": None,
11
+ "coins": 0,
12
+ "wins": 0,
13
+ "losses": 0,
14
+ "inventory": [],
15
+ "created_at": datetime.now().isoformat(),
16
+ "last_login": datetime.now().isoformat()
17
+ }
18
+
19
+ def create_box(name):
20
+ """Create a new box with random stats"""
21
+ box = Box(name=name)
22
+
23
+ # Random base stats
24
+ box.attack = random.randint(8, 15)
25
+ box.defense = random.randint(6, 12)
26
+ box.health = random.randint(40, 60)
27
+ box.max_health = box.health
28
+ box.speed = random.randint(3, 8)
29
+
30
+ # Random ability
31
+ abilities = [
32
+ {"name": "Power Strike", "damage_bonus": 5, "description": "Extra damage on attacks"},
33
+ {"name": "Iron Shield", "defense_bonus": 3, "description": "Better defense"},
34
+ {"name": "Quick Attack", "speed_bonus": 2, "description": "Faster attacks"},
35
+ {"name": "Regeneration", "heal_bonus": 2, "description": "Heals over time"},
36
+ {"name": "Critical Hit", "crit_chance": 0.2, "description": "Chance for double damage"}
37
+ ]
38
+ box.ability = random.choice(abilities)
39
+
40
+ return box
41
+
42
+ def calculate_battle_result(attacker, defender):
43
+ """Calculate battle result between two boxes"""
44
+ battle_log = []
45
+ rounds = 0
46
+ max_rounds = 20
47
+
48
+ attacker_health = attacker.health
49
+ defender_health = defender.health
50
+
51
+ # Determine who goes first
52
+ attacker_first = attacker.speed >= defender.speed
53
+
54
+ while attacker_health > 0 and defender_health > 0 and rounds < max_rounds:
55
+ rounds += 1
56
+ battle_log.append(f"\n--- Round {rounds} ---")
57
+
58
+ if attacker_first:
59
+ # Attacker's turn
60
+ damage = max(1, attacker.attack - defender.defense + random.randint(-2, 3))
61
+
62
+ # Apply ability bonus
63
+ if "damage_bonus" in attacker.ability:
64
+ damage += attacker.ability["damage_bonus"]
65
+ battle_log.append(f"{attacker.name} uses {attacker.ability['name']}!")
66
+
67
+ # Critical hit chance
68
+ if "crit_chance" in attacker.ability and random.random() < attacker.ability["crit_chance"]:
69
+ damage *= 2
70
+ battle_log.append(f"💥 CRITICAL HIT!")
71
+
72
+ defender_health -= damage
73
+ battle_log.append(f"{attacker.name} deals {damage} damage to {defender.name}")
74
+ battle_log.append(f"{defender.name} health: {max(0, defender_health)}/{defender.max_health}")
75
+
76
+ if defender_health <= 0:
77
+ break
78
+
79
+ # Defender's turn
80
+ damage = max(1, defender.attack - attacker.defense + random.randint(-2, 3))
81
+
82
+ # Apply ability bonus
83
+ if "damage_bonus" in defender.ability:
84
+ damage += defender.ability["damage_bonus"]
85
+ battle_log.append(f"{defender.name} uses {defender.ability['name']}!")
86
+
87
+ # Critical hit chance
88
+ if "crit_chance" in defender.ability and random.random() < defender.ability["crit_chance"]:
89
+ damage *= 2
90
+ battle_log.append(f"💥 CRITICAL HIT!")
91
+
92
+ attacker_health -= damage
93
+ battle_log.append(f"{defender.name} deals {damage} damage to {attacker.name}")
94
+ battle_log.append(f"{attacker.name} health: {max(0, attacker_health)}/{attacker.max_health}")
95
+ else:
96
+ # Defender goes first (same logic as above but reversed)
97
+ damage = max(1, defender.attack - attacker.defense + random.randint(-2, 3))
98
+
99
+ if "damage_bonus" in defender.ability:
100
+ damage += defender.ability["damage_bonus"]
101
+ battle_log.append(f"{defender.name} uses {defender.ability['name']}!")
102
+
103
+ if "crit_chance" in defender.ability and random.random() < defender.ability["crit_chance"]:
104
+ damage *= 2
105
+ battle_log.append(f"💥 CRITICAL HIT!")
106
+
107
+ attacker_health -= damage
108
+ battle_log.append(f"{defender.name} deals {damage} damage to {attacker.name}")
109
+ battle_log.append(f"{attacker.name} health: {max(0, attacker_health)}/{attacker.max_health}")
110
+
111
+ if attacker_health <= 0:
112
+ break
113
+
114
+ damage = max(1, attacker.attack - defender.defense + random.randint(-2, 3))
115
+
116
+ if "damage_bonus" in attacker.ability:
117
+ damage += attacker.ability["damage_bonus"]
118
+ battle_log.append(f"{attacker.name} uses {attacker.ability['name']}!")
119
+
120
+ if "crit_chance" in attacker.ability and random.random() < attacker.ability["crit_chance"]:
121
+ damage *= 2
122
+ battle_log.append(f"💥 CRITICAL HIT!")
123
+
124
+ defender_health -= damage
125
+ battle_log.append(f"{attacker.name} deals {damage} damage to {defender.name}")
126
+ battle_log.append(f"{defender.name} health: {max(0, defender_health)}/{defender.max_health}")
127
+
128
+ # Determine winner
129
+ if attacker_health > 0 and defender_health <= 0:
130
+ winner = "attacker"
131
+ battle_log.append(f"\n🎉 {attacker.name} WINS!")
132
+ elif defender_health > 0 and attacker_health <= 0:
133
+ winner = "defender"
134
+ battle_log.append(f"\n💀 {defender.name} WINS!")
135
+ else:
136
+ # Draw or max rounds reached
137
+ winner = "draw"
138
+ if attacker_health > defender_health:
139
+ winner = "attacker"
140
+ battle_log.append(f"\n⏰ Time's up! {attacker.name} wins by health!")
141
+ elif defender_health > attacker_health:
142
+ winner = "defender"
143
+ battle_log.append(f"\n⏰ Time's up! {defender.name} wins by health!")
144
+ else:
145
+ battle_log.append(f"\n🤝 It's a DRAW!")
146
+
147
+ return {
148
+ "winner": "user" if winner == "attacker" else "opponent" if winner == "defender" else "draw",
149
+ "log": "\n".join(battle_log),
150
+ "rounds": rounds
151
+ }
152
+
153
+ def get_shop_items():
154
+ """Get available shop items"""
155
+ return [
156
+ {
157
+ "name": "Power Boost",
158
+ "cost": 50,
159
+ "description": "Increase attack by 3",
160
+ "effect": "attack +3",
161
+ "type": "attack"
162
+ },
163
+ {
164
+ "name": "Defense Shield",
165
+ "cost": 40,
166
+ "description": "Increase defense by 3",
167
+ "effect": "defense +3",
168
+ "type": "defense"
169
+ },
170
+ {
171
+ "name": "Health Potion",
172
+ "cost": 30,
173
+ "description": "Restore 20 health",
174
+ "effect": "health +20",
175
+ "type": "health"
176
+ },
177
+ {
178
+ "name": "Speed Boots",
179
+ "cost": 60,
180
+ "description": "Increase speed by 2",
181
+ "effect": "speed +2",
182
+ "type": "speed"
183
+ },
184
+ {
185
+ "name": "Mystery Box",
186
+ "cost": 100,
187
+ "description": "Random stat boost",
188
+ "effect": "random +5",
189
+ "type": "mystery"
190
+ },
191
+ {
192
+ "name": "XP Boost",
193
+ "cost": 80,
194
+ "description": "Gain 50 XP instantly",
195
+ "effect": "xp +50",
196
+ "type": "xp"
197
+ },
198
+ {
199
+ "name": "Coin Pouch",
200
+ "cost": 20,
201
+ "description": "Get 30 coins",
202
+ "effect": "coins +30",
203
+ "type": "coins"
204
+ },
205
+ {
206
+ "name": "Ability Upgrade",
207
+ "cost": 150,
208
+ "description": "Upgrade your ability",
209
+ "effect": "ability ++",
210
+ "type": "ability"
211
+ },
212
+ {
213
+ "name": "Max Health Boost",
214
+ "cost": 70,
215
+ "description": "Increase max health by 15",
216
+ "effect": "max_health +15",
217
+ "type": "max_health"
218
+ },
219
+ {
220
+ "name": "Lucky Charm",
221
+ "cost": 90,
222
+ "description": "Increase critical hit chance",
223
+ "effect": "crit +10%",
224
+ "type": "crit"
225
+ }
226
+ ]
227
+
228
+ def purchase_item(user_data, item):
229
+ """Purchase an item from the shop"""
230
+ if user_data["coins"] < item["cost"]:
231
+ return {"success": False, "message": "Not enough coins!"}
232
+
233
+ box = user_data.get("box")
234
+ if not box:
235
+ return {"success": False, "message": "Create a box first!"}
236
+
237
+ user_data["coins"] -= item["cost"]
238
+
239
+ # Apply item effect
240
+ if item["type"] == "attack":
241
+ box.attack += 3
242
+ message = f"Attack increased to {box.attack}!"
243
+ elif item["type"] == "defense":
244
+ box.defense += 3
245
+ message = f"Defense increased to {box.defense}!"
246
+ elif item["type"] == "health":
247
+ box.health = min(box.max_health, box.health + 20)
248
+ message = f"Health restored to {box.health}!"
249
+ elif item["type"] == "speed":
250
+ box.speed += 2
251
+ message = f"Speed increased to {box.speed}!"
252
+ elif item["type"] == "mystery":
253
+ stat = random.choice(["attack", "defense", "speed"])
254
+ if stat == "attack":
255
+ box.attack += 5
256
+ message = f"Mystery box gave +5 attack!"
257
+ elif stat == "defense":
258
+ box.defense += 5
259
+ message = f"Mystery box gave +5 defense!"
260
+ else:
261
+ box.speed += 5
262
+ message = f"Mystery box gave +5 speed!"
263
+ elif item["type"] == "xp":
264
+ box.gain_xp(50)
265
+ message = f"Gained 50 XP! Current level: {box.level}"
266
+ elif item["type"] == "coins":
267
+ user_data["coins"] += 30
268
+ message = f"Received 30 coins! Total: {user_data['coins']}"
269
+ elif item["type"] == "ability":
270
+ box.ability["level"] = box.ability.get("level", 1) + 1
271
+ message = f"Ability upgraded to level {box.ability['level']}!"
272
+ elif item["type"] == "max_health":
273
+ box.max_health += 15
274
+ box.health += 15
275
+ message = f"Max health increased to {box.max_health}!"
276
+ elif item["type"] == "crit":
277
+ if "crit_chance" not in box.ability:
278
+ box.ability["crit_chance"] = 0.1
279
+ else:
280
+ box.ability["crit_chance"] = min(0.5, box.ability["crit_chance"] + 0.1)
281
+ message = f"Critical hit chance increased to {box.ability['crit_chance']*100:.0f}%!"
282
+
283
+ user_data["inventory"].append(item["name"])
284
+
285
+ return {"success": True, "message": message}
286
+
287
+ def get_leaderboard(game_state):
288
+ """Get the global leaderboard"""
289
+ players = []
290
+
291
+ for user_id, data in game_state.items():
292
+ if data.get("box"):
293
+ players.append({
294
+ "name": user_id,
295
+ "box_name": data["box"].name,
296
+ "level": data["box"].level,
297
+ "wins": data.get("wins", 0),
298
+ "losses": data.get("losses", 0),
299
+ "total_battles": data.get("wins", 0) + data.get("losses", 0)
300
+ })
301
+
302
+ # Sort by wins, then by win rate
303
+ players.sort(key=lambda x: (x["wins"], x["wins"]/(x["losses"]+1) if x["losses"] > 0 else x["wins"]), reverse=True)
304
+
305
+ return players
306
+
307
+ def save_game_state(game_state, filename="game_state.json"):
308
+ """Save game state to file"""
309
+ try:
310
+ with open(filename, 'w') as f:
311
+ json.dump(game_state, f, default=str)
312
+ return True
313
+ except:
314
+ return False
315
+
316
+ def load_game_state(filename="game_state.json"):
317
+ """Load game state from file"""
318
+ try:
319
+ with open(filename, 'r') as f:
320
+ return json.load(f)
321
+ except:
322
+ return {}