Mxltic's picture
Update app.py
d11afe9 verified
import gradio as gr
import random
import time
from typing import Dict, List, Tuple
# Game state storage
game_rooms = {}
class Player:
def __init__(self, name: str):
self.name = name
self.hp = 100
self.max_hp = 100
self.attack = 15
self.potions = 3
self.gold = 0
self.x = 0
self.y = 0
self.level = 1
self.exp = 0
class Room:
def __init__(self, x: int, y: int):
self.x = x
self.y = y
self.monster = None
self.treasure = None
self.explored = False
self.generate_content()
def generate_content(self):
rand = random.randint(1,100)
if rand <= 50:
monsters = [
("Goblin", 30, 8, 10, 15),
("Orc", 50, 12, 20, 25),
("Skeleton", 40, 10, 15, 20),
("Dark Mage", 35, 15, 25, 30),
("Dragon Whelp", 60, 18, 30, 40)
]
name, hp, atk, gold, exp = random.choice(monsters)
self.monster = {"name": name, "hp": hp, "max_hp": hp, "attack": atk, "gold": gold, "exp": exp}
elif rand <= 75:
self.treasure = random.randint(10, 40)
elif rand <= 90:
self.treasure = "potion"
elif rand <= 95:
self.treasure = "weapon"
class GameRoom:
def __init__(self, room_id: str):
self.room_id = room_id
self.players: Dict[str, Player] = {}
self.grid: Dict[Tuple[int, int], Room] = {}
self.current_player = ""
self.turn_count = 0
self.battle_active = False
self.current_monster = None
self.log = ["🏰 Game dimulai! Gabung sekarang!"]
# Generate dungeon grid (7x7 for more exploration)
for x in range(7):
for y in range(7):
self.grid[(x, y)] = Room(x, y)
# Place exit
exit_x, exit_y = 6, 6
self.grid[(exit_x, exit_y)].treasure = "exit"
# Place special rooms
self.grid[(3, 3)].treasure = "boss"
self.grid[(0, 6)].treasure = "artifact"
def add_player(self, player_name: str) -> str:
if player_name in self.players:
return f"{player_name} sudah ada dalam room!"
if len(self.players) >= 4:
return "Room penuh! Maksimal 4 pemain."
self.players[player_name] = Player(player_name)
self.log.append(f"🎮 {player_name} bergabung dalam petualangan!")
if not self.current_player:
self.current_player = player_name
self.log.append(f"👑 {player_name} memulai petualangan!")
return f"🎉 {player_name} berhasil bergabung!"
def get_player_status(self, player_name: str) -> str:
if player_name not in self.players:
return "Pemain tidak ditemukan!"
p = self.players[player_name]
# Create HP bar
hp_percent = (p.hp / p.max_hp) * 100
hp_bar = self.create_progress_bar(hp_percent, "❤️")
exp_bar = self.create_progress_bar(p.exp, "🌟")
return f"""
<div style="background: linear-gradient(135deg, #2c3e50, #4a69bd); padding: 15px; border-radius: 10px; color: white; border: 2px solid #f39c12;">
<h3 style="margin: 0 0 10px 0; color: #f39c12;">🏹 {p.name}</h3>
{hp_bar}
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 8px; margin-top: 10px;">
<div>⚔️ <strong>Attack:</strong> {p.attack}</div>
<div>🧪 <strong>Potions:</strong> {p.potions}</div>
<div>💰 <strong>Gold:</strong> {p.gold}</div>
<div>🎯 <strong>Level:</strong> {p.level}</div>
</div>
{exp_bar}
<div style="margin-top: 8px;">📍 <strong>Position:</strong> ({p.x}, {p.y})</div>
</div>
"""
def create_progress_bar(self, percent, label):
width = min(percent, 100)
color = "#2ecc71" if percent > 70 else "#f39c12" if percent > 30 else "#e74c3c"
return f"""
<div style="margin: 5px 0;">
<div style="display: flex; justify-content: between; font-size: 12px;">
<span>{label}</span>
<span>{percent:.1f}%</span>
</div>
<div style="background: #34495e; height: 8px; border-radius: 4px; overflow: hidden;">
<div style="background: {color}; height: 100%; width: {width}%; border-radius: 4px;"></div>
</div>
</div>
"""
def move_player(self, player_name: str, direction: str) -> Tuple[bool, str]:
if player_name != self.current_player:
return False, "❌ Bukan giliranmu!"
if player_name not in self.players:
return False, "❌ Pemain tidak ada!"
if self.battle_active:
return False, "❌ Sedang dalam pertarungan!"
p = self.players[player_name]
new_x, new_y = p.x, p.y
if direction == "utara" and p.y > 0:
new_y -= 1
elif direction == "selatan" and p.y < 6:
new_y += 1
elif direction == "barat" and p.x > 0:
new_x -= 1
elif direction == "timur" and p.x < 6:
new_x += 1
else:
return False, "❌ Tidak bisa bergerak ke arah itu!"
p.x, p.y = new_x, new_y
room = self.grid[(new_x, new_y)]
if not room.explored:
room.explored = True
self.log.append(f"🔍 {p.name} menemukan ruangan ({new_x}, {new_y})")
if room.monster:
self.battle_active = True
self.current_monster = room.monster
return True, self.create_battle_alert(f"⚔️ {room.monster['name']} muncul!", f"❤️ HP: {room.monster['hp']} | ⚔️ Attack: {room.monster['attack']}")
elif room.treasure:
if room.treasure == "potion":
p.potions += 1
self.log.append(f"🧪 {p.name} menemukan ramuan penyembuh!")
return True, self.create_success_alert("🧪 Kamu menemukan ramuan penyembuh!")
elif room.treasure == "weapon":
p.attack += 5
self.log.append(f"⚔️ {p.name} menemukan senjata legendaris! Attack +5")
return True, self.create_success_alert("⚔️ Kamu menemukan senjata legendaris! Attack +5")
elif room.treasure == "exit":
self.log.append(f"🎉 {p.name} menemukan pintu keluar! Kemenangan!")
return True, self.create_victory_alert("🎉 Selamat! Kamu menemukan pintu keluar!")
elif room.treasure == "boss":
boss = {"name": "Dragon Lord", "hp": 100, "max_hp": 100, "attack": 25, "gold": 100, "exp": 100}
self.battle_active = True
self.current_monster = boss
return True, self.create_battle_alert("🐉 BOSS BESAR! Dragon Lord muncul!", f"❤️ HP: {boss['hp']} | ⚔️ Attack: {boss['attack']}")
elif room.treasure == "artifact":
p.max_hp += 25
p.hp = p.max_hp
self.log.append(f"💎 {p.name} menemukan artifact! Max HP +25")
return True, self.create_success_alert("💎 Kamu menemukan artifact kuno! Max HP +25")
else:
p.gold += room.treasure
self.log.append(f"💰 {p.name} menemukan {room.treasure} emas!")
return True, self.create_success_alert(f"💰 Kamu menemukan {room.treasure} emas!")
return True, "📍 Bergerak ke ruangan yang sudah dijelajahi."
def create_battle_alert(self, title, content):
return f"""
<div style="background: linear-gradient(135deg, #e74c3c, #c0392b); padding: 15px; border-radius: 10px; color: white; border: 2px solid #f1c40f; text-align: center;">
<h3 style="margin: 0 0 10px 0;">{title}</h3>
<p style="margin: 0; font-size: 14px;">{content}</p>
</div>
"""
def create_success_alert(self, message):
return f"""
<div style="background: linear-gradient(135deg, #27ae60, #2ecc71); padding: 15px; border-radius: 10px; color: white; border: 2px solid #f1c40f; text-align: center;">
<h3 style="margin: 0;">{message}</h3>
</div>
"""
def create_victory_alert(self, message):
return f"""
<div style="background: linear-gradient(135deg, #f39c12, #e67e22); padding: 20px; border-radius: 10px; color: white; border: 3px solid #f1c40f; text-align: center;">
<h2 style="margin: 0;">🎉 {message} 🎉</h2>
</div>
"""
def battle_action(self, player_name: str, action: str) -> Tuple[bool, str]:
if player_name != self.current_player:
return False, "❌ Bukan giliranmu!"
if not self.battle_active:
return False, "❌ Tidak ada pertarungan!"
p = self.players[player_name]
m = self.current_monster
if action == "attack":
dmg = random.randint(p.attack-3, p.attack+5)
m["hp"] -= dmg
msg = f"<div style='text-align: center;'><h3>⚔️ {p.name} menyerang {m['name']}!</h3><p>💥 Damage: <strong>{dmg}</strong></p>"
if m["hp"] <= 0:
p.gold += m["gold"]
p.exp += m["exp"]
msg += f"<p>💀 <strong>{m['name']} dikalahkan!</strong></p><p>💰 +{m['gold']} emas | 🌟 +{m['exp']} EXP</p>"
# Level up check
if p.exp >= 100:
p.level += 1
p.exp = 0
p.max_hp += 10
p.hp = p.max_hp
p.attack += 3
msg += f"<p>🎉 <strong>LEVEL UP!</strong> Sekarang Level {p.level}!</p>"
self.battle_active = False
self.current_monster = None
self.log.append(f"🎯 {p.name} mengalahkan {m['name']}!")
else:
mdmg = random.randint(m["attack"]-2, m["attack"]+3)
p.hp -= mdmg
msg += f"<p>🩸 <strong>{m['name']}</strong> menyerang balik!</p><p>💔 Damage: <strong>{mdmg}</strong></p>"
self.log.append(f"⚔️ Pertarungan {p.name} vs {m['name']}!")
if p.hp <= 0:
self.log.append(f"💀 {p.name} tewas dalam pertarungan!")
return True, self.create_battle_alert("💀 Kamu tewas dalam pertempuran!", "Game over!")
msg += "</div>"
elif action == "potion":
if p.potions > 0:
heal = random.randint(25, 40)
p.hp = min(p.hp + heal, p.max_hp)
p.potions -= 1
msg = f"<div style='text-align: center;'><h3>🧪 {p.name} menggunakan ramuan!</h3><p>💚 +{heal} HP</p>"
mdmg = random.randint(m["attack"]-2, m["attack"]+3)
p.hp -= mdmg
msg += f"<p>🩸 <strong>{m['name']}</strong> menyerang!</p><p>💔 Damage: <strong>{mdmg}</strong></p>"
if p.hp <= 0:
self.log.append(f"💀 {p.name} tewas setelah menggunakan ramuan!")
return True, self.create_battle_alert("💀 Kamu tewas dalam pertempuran!", "Game over!")
msg += "</div>"
else:
return False, "❌ Tidak punya ramuan!"
elif action == "flee":
flee_chance = random.randint(1, 100)
if flee_chance > 50:
self.battle_active = False
self.current_monster = None
msg = self.create_success_alert("🏃‍♂️ Kamu berhasil melarikan diri!")
self.log.append(f"🏃‍♂️ {p.name} melarikan diri dari pertarungan!")
else:
mdmg = random.randint(m["attack"]-2, m["attack"]+3)
p.hp -= mdmg
msg = f"<div style='text-align: center; background: #e74c3c; padding: 15px; border-radius: 10px; color: white;'><h3>❌ Gagal melarikan diri!</h3><p>🩸 {m['name']} menyerang! Damage: {mdmg}</p></div>"
if p.hp <= 0:
self.log.append(f"💀 {p.name} tewas saat mencoba melarikan diri!")
return True, self.create_battle_alert("💀 Kamu tewas dalam pertempuran!", "Game over!")
return True, msg
def end_turn(self, player_name: str) -> Tuple[bool, str]:
if player_name != self.current_player:
return False, "❌ Bukan giliranmu!"
player_names = list(self.players.keys())
if len(player_names) <= 1:
return False, "❌ Butuh minimal 2 pemain!"
current_idx = player_names.index(player_name)
next_idx = (current_idx + 1) % len(player_names)
self.current_player = player_names[next_idx]
self.turn_count += 1
# Heal 5 HP at turn start
p = self.players[self.current_player]
old_hp = p.hp
p.hp = min(p.hp + 5, p.max_hp)
heal_amount = p.hp - old_hp
self.log.append(f"🔄 Giliran {self.current_player} (+{heal_amount} HP)")
return True, f"""
<div style="background: linear-gradient(135deg, #9b59b6, #8e44ad); padding: 15px; border-radius: 10px; color: white; text-align: center;">
<h3>✅ Giliran {self.current_player}!</h3>
<p>+{heal_amount} HP regenerasi</p>
</div>
"""
def create_dungeon_map_html(self) -> str:
html = """
<div style="background: #2c3e50; padding: 15px; border-radius: 10px; border: 2px solid #f39c12;">
<h3 style="color: white; text-align: center; margin-bottom: 15px;">🗺️ Peta Dungeon</h3>
<div style="display: grid; grid-template-columns: repeat(7, 1fr); gap: 4px; background: #34495e; padding: 10px; border-radius: 5px;">
"""
for y in range(7):
for x in range(7):
room = self.grid[(x, y)]
players_here = [p for p in self.players.values() if p.x == x and p.y == y]
room_class = "room "
room_text = "?"
room_title = f"Position: ({x}, {y})"
if players_here:
room_class += "player-room"
room_text = "👤"
room_title += f"\nPlayers: {', '.join([p.name for p in players_here])}"
elif room.treasure == "exit":
room_class += "exit-room"
room_text = "🚪"
room_title += "\nEXIT"
elif room.treasure == "boss":
room_class += "boss-room"
room_text = "🐉"
room_title += "\nBOSS ROOM"
elif room.treasure == "artifact":
room_class += "artifact-room"
room_text = "💎"
room_title += "\nARTIFACT"
elif room.monster and not room.explored:
room_class += "monster-room"
room_text = "👹"
room_title += f"\nMonster: {room.monster['name']}"
elif room.treasure and not room.explored and room.treasure not in ["exit", "boss", "artifact"]:
if room.treasure == "potion":
room_class += "potion-room"
room_text = "🧪"
room_title += "\nPotion"
elif room.treasure == "weapon":
room_class += "weapon-room"
room_text = "⚔️"
room_title += "\nWeapon"
else:
room_class += "treasure-room"
room_text = "💰"
room_title += f"\nGold: {room.treasure}"
elif room.explored:
room_class += "explored-room"
room_text = "✓"
room_title += "\nExplored"
else:
room_class += "unexplored-room"
room_text = "?"
room_title += "\nUnexplored"
html += f"""
<div class="{room_class}" title="{room_title}" style="
width: 40px; height: 40px; display: flex; align-items: center; justify-content: center;
border-radius: 5px; font-size: 16px; cursor: pointer; border: 1px solid #7f8c8d;
">{room_text}</div>
"""
html += """
</div>
<div style="margin-top: 15px; display: grid; grid-template-columns: repeat(3, 1fr); gap: 5px; color: white; font-size: 12px;">
<div>👤 = Pemain</div>
<div>🚪 = Exit</div>
<div>🐉 = Boss</div>
<div>👹 = Monster</div>
<div>💰 = Treasure</div>
<div>🧪 = Potion</div>
</div>
</div>
<style>
.player-room { background: #f39c12; color: black; }
.exit-room { background: #27ae60; color: white; }
.boss-room { background: #e74c3c; color: white; animation: pulse 2s infinite; }
.artifact-room { background: #9b59b6; color: white; }
.monster-room { background: #e67e22; color: white; }
.treasure-room { background: #f1c40f; color: black; }
.potion-room { background: #3498db; color: white; }
.weapon-room { background: #95a5a6; color: white; }
.explored-room { background: #34495e; color: #bdc3c7; }
.unexplored-room { background: #2c3e50; color: #7f8c8d; }
@keyframes pulse {
0% { transform: scale(1); }
50% { transform: scale(1.1); }
100% { transform: scale(1); }
}
</style>
"""
return html
def get_all_players_html(self) -> str:
if not self.players:
return "<div style='color: #7f8c8d; text-align: center;'>Belum ada pemain</div>"
html = """
<div style="background: linear-gradient(135deg, #34495e, #2c3e50); padding: 15px; border-radius: 10px; border: 2px solid #f39c12;">
<h3 style="color: white; margin-top: 0; text-align: center;">👥 Tim Petualang</h3>
"""
for name, p in self.players.items():
current = "👑" if name == self.current_player else "👤"
hp_percent = (p.hp / p.max_hp) * 100
hp_color = "#2ecc71" if hp_percent > 70 else "#f39c12" if hp_percent > 30 else "#e74c3c"
html += f"""
<div style="background: #2c3e50; padding: 10px; margin: 8px 0; border-radius: 8px; border-left: 4px solid {hp_color};">
<div style="display: flex; justify-content: between; align-items: center; color: white;">
<span style="font-weight: bold; font-size: 16px;">{current} {name}</span>
<span style="font-size: 12px;">Lvl {p.level}</span>
</div>
<div style="color: #bdc3c7; font-size: 12px; margin-top: 5px;">
❤️ {p.hp}/{p.max_hp} | ⚔️ {p.attack} | 💰 {p.gold}
</div>
</div>
"""
html += "</div>"
return html
def get_logs_html(self) -> str:
logs = self.log[-8:] if self.log else ["Tidak ada aktivitas"]
html = """
<div style="background: #1a1a1a; padding: 15px; border-radius: 10px; border: 2px solid #f39c12; height: 200px; overflow-y: auto;">
<h3 style="color: white; margin-top: 0; text-align: center;">📜 Catatan Petualangan</h3>
"""
for log in logs:
html += f"""
<div style="color: #bdc3c7; padding: 5px 0; border-bottom: 1px solid #2c3e50; font-size: 14px;">
{log}
</div>
"""
html += "</div>"
return html
# Gradio interface dengan tema yang lebih keren
def create_interface():
with gr.Blocks(
title="Dungeon Crawler RPG",
theme=gr.themes.Soft(primary_hue="red", secondary_hue="slate"),
css="""
.dungeon-title {
text-align: center;
background: linear-gradient(45deg, #8B4513, #D2691E);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
font-weight: bold;
font-size: 2.5em;
text-shadow: 2px 2px 4px rgba(0,0,0,0.3);
}
.game-container {
border: 2px solid #8B4513;
border-radius: 10px;
padding: 15px;
background: #f5f5dc;
box-shadow: 0 4px 6px rgba(0,0,0,0.1);
}
"""
) as demo:
gr.Markdown("""
<div class='dungeon-title'>🏰 Dungeon Crawler RPG</div>
<div style='text-align: center; color: #666; margin-bottom: 20px; font-size: 16px;'>
Petualangan Multiplayer - Jelajahi dungeon, kalahkan monster, dan temukan harta karun!
</div>
""")
with gr.Row():
with gr.Column(scale=1):
with gr.Group():
gr.Markdown("### 🎮 Masuk Game")
room_id = gr.Textbox(
label="🏠 Room ID",
placeholder="Masukkan Room ID (contoh: dragon_lair)",
info="Buat room baru atau gabung yang sudah ada"
)
player_name = gr.Textbox(
label="👤 Nama Petualang",
placeholder="Nama pahlawan kamu",
info="Gunakan nama yang keren!"
)
join_btn = gr.Button("🚪 Masuk Dungeon", variant="primary", size="lg")
with gr.Column(scale=2):
with gr.Group():
gr.Markdown("### 📊 Status Petualang")
status_box = gr.HTML(label="Status", value="<div style='text-align: center; color: #666;'>Bergabunglah untuk memulai...</div>")
with gr.Row():
with gr.Column(scale=2):
with gr.Group():
gr.Markdown("### 🗺️ Peta Dungeon")
map_box = gr.HTML(label="Peta")
with gr.Column(scale=1):
with gr.Group():
gr.Markdown("### 👥 Tim Petualang")
players_box = gr.HTML(label="Pemain")
with gr.Group():
gr.Markdown("### 🔄 Kontrol Game")
turn_info = gr.HTML(label="Giliran", value="<div style='text-align: center; color: #666;'>Menunggu pemain...</div>")
with gr.Row():
refresh_btn = gr.Button("🔄 Refresh", variant="secondary")
end_turn_btn = gr.Button("⏭️ Akhiri Giliran", variant="primary")
with gr.Row():
with gr.Column(scale=1):
with gr.Group():
gr.Markdown("### 🎯 Aksi Petualangan")
with gr.Row():
move_choice = gr.Radio(
choices=["⬆️ Utara", "⬇️ Selatan", "⬅️ Barat", "➡️ Timur"],
label="🚶 Arah Gerakan",
value="⬆️ Utara"
)
move_btn = gr.Button("🎯 Jelajahi", variant="primary", size="lg")
with gr.Column(scale=1):
with gr.Group():
gr.Markdown("### ⚔️ Aksi Pertempuran")
battle_choice = gr.Radio(
choices=["⚔️ Serang", "🧪 Gunakan Ramuan", "🏃‍♂️ Kabur"],
label="Pilih Strategi",
value="⚔️ Serang"
)
battle_btn = gr.Button("⚡ Eksekusi", variant="primary", size="lg")
with gr.Row():
with gr.Group():
gr.Markdown("### 📜 Catatan Petualangan")
log_box = gr.HTML(label="Activity Log")
# Event handlers
def join_room(room_id_str, name_str):
if not room_id_str or not name_str:
return (
"❌ Room ID dan nama harus diisi!",
"<div style='text-align: center; color: #666;'>Bergabunglah untuk memulai...</div>",
"<div style='text-align: center; color: #666;'>Peta akan muncul di sini...</div>",
"<div style='color: #7f8c8d; text-align: center;'>Belum ada pemain</div>",
"<div style='text-align: center; color: #666;'>Menunggu pemain...</div>",
"<div style='text-align: center; color: #666;'>Log akan muncul di sini...</div>"
)
if room_id_str not in game_rooms:
game_rooms[room_id_str] = GameRoom(room_id_str)
room = game_rooms[room_id_str]
result = room.add_player(name_str)
status = room.get_player_status(name_str)
turn = f"<div style='background: linear-gradient(135deg, #f39c12, #e67e22); padding: 10px; border-radius: 8px; color: white; text-align: center;'><strong>👑 Giliran:</strong> {room.current_player}</div>"
map_html = room.create_dungeon_map_html()
players = room.get_all_players_html()
logs = room.get_logs_html()
return result, status, map_html, players, turn, logs
def handle_move(room_id_str, name_str, direction):
direction = direction.replace("⬆️ ", "").replace("⬇️ ", "").replace("⬅️ ", "").replace("➡️ ", "").lower()
if not room_id_str or not name_str:
return "❌ Room ID dan nama harus diisi!", "", "", ""
if room_id_str not in game_rooms:
return "❌ Room tidak ditemukan!", "", "", ""
room = game_rooms[room_id_str]
success, msg = room.move_player(name_str, direction)
status = room.get_player_status(name_str)
map_html = room.create_dungeon_map_html()
logs = room.get_logs_html()
return msg, status, map_html, logs
def handle_battle(room_id_str, name_str, action):
action_map = {
"⚔️ Serang": "attack",
"🧪 Gunakan Ramuan": "potion",
"🏃‍♂️ Kabur": "flee"
}
action = action_map.get(action, "attack")
if not room_id_str or not name_str:
return "❌ Room ID dan nama harus diisi!", "", "", ""
if room_id_str not in game_rooms:
return "❌ Room tidak ditemukan!", "", "", ""
room = game_rooms[room_id_str]
success, msg = room.battle_action(name_str, action)
status = room.get_player_status(name_str)
map_html = room.create_dungeon_map_html()
logs = room.get_logs_html()
return msg, status, map_html, logs
def handle_end_turn(room_id_str, name_str):
if not room_id_str or not name_str:
return "❌ Room ID dan nama harus diisi!", "", "", "", ""
if room_id_str not in game_rooms:
return "❌ Room tidak ditemukan!", "", "", "", ""
room = game_rooms[room_id_str]
success, msg = room.end_turn(name_str)
turn = f"<div style='background: linear-gradient(135deg, #f39c12, #e67e22); padding: 10px; border-radius: 8px; color: white; text-align: center;'><strong>👑 Giliran:</strong> {room.current_player}</div>"
map_html = room.create_dungeon_map_html()
players = room.get_all_players_html()
logs = room.get_logs_html()
return msg, turn, map_html, players, logs
def refresh_all(room_id_str, name_str):
if not room_id_str or not name_str:
return "", "", "", ""
if room_id_str not in game_rooms:
return "", "", "", ""
room = game_rooms[room_id_str]
status = room.get_player_status(name_str)
turn = f"<div style='background: linear-gradient(135deg, #f39c12, #e67e22); padding: 10px; border-radius: 8px; color: white; text-align: center;'><strong>👑 Giliran:</strong> {room.current_player}</div>"
map_html = room.create_dungeon_map_html()
logs = room.get_logs_html()
return status, turn, map_html, logs
# Event handlers
join_btn.click(
fn=join_room,
inputs=[room_id, player_name],
outputs=[status_box, status_box, map_box, players_box, turn_info, log_box]
)
move_btn.click(
fn=handle_move,
inputs=[room_id, player_name, move_choice],
outputs=[status_box, status_box, map_box, log_box]
)
battle_btn.click(
fn=handle_battle,
inputs=[room_id, player_name, battle_choice],
outputs=[status_box, status_box, map_box, log_box]
)
end_turn_btn.click(
fn=handle_end_turn,
inputs=[room_id, player_name],
outputs=[status_box, turn_info, map_box, players_box, log_box]
)
refresh_btn.click(
fn=refresh_all,
inputs=[room_id, player_name],
outputs=[status_box, turn_info, map_box, log_box]
)
return demo
# Create and launch the interface
if __name__ == "__main__":
demo = create_interface()
demo.launch(share=True)