Spaces:
Sleeping
Sleeping
import streamlit as st | |
import os | |
import random | |
import time | |
from PIL import Image | |
import json | |
from datetime import datetime | |
from pathlib import Path | |
import base64 | |
from io import BytesIO | |
# Constants for game board | |
GRID_WIDTH = 16 | |
GRID_HEIGHT = 9 | |
REFRESH_RATE = 5 # seconds | |
# Fantasy name generator | |
def generate_fantasy_name(): | |
prefixes = ['Aer', 'Bal', 'Cal', 'Dor', 'El', 'Fae', 'Gor', 'Hel', 'Il', 'Jor', | |
'Kal', 'Lyr', 'Mel', 'Nym', 'Oro', 'Pyr', 'Qar', 'Ryn', 'Syl', 'Tyr'] | |
suffixes = ['ian', 'or', 'ion', 'us', 'ix', 'ar', 'en', 'yr', 'el', 'an', | |
'is', 'ax', 'on', 'ir', 'ex', 'az', 'er', 'eth', 'ys', 'ix'] | |
return random.choice(prefixes) + random.choice(suffixes) | |
# Initialize session state | |
if 'initialized' not in st.session_state: | |
st.session_state.initialized = False | |
st.session_state.game_state = { | |
'players': {}, | |
'chat_messages': [], | |
'last_sync': time.time() | |
} | |
st.session_state.player_name = None | |
st.session_state.character_stats = None | |
st.session_state.position = { | |
'x': random.randint(0, GRID_WIDTH - 1), | |
'y': random.randint(0, GRID_HEIGHT - 1) | |
} | |
st.session_state.last_move = time.time() | |
def roll_stats(): | |
return { | |
'STR': sum(sorted([random.randint(1, 6) for _ in range(4)])[1:]), | |
'DEX': sum(sorted([random.randint(1, 6) for _ in range(4)])[1:]), | |
'CON': sum(sorted([random.randint(1, 6) for _ in range(4)])[1:]), | |
'INT': sum(sorted([random.randint(1, 6) for _ in range(4)])[1:]), | |
'WIS': sum(sorted([random.randint(1, 6) for _ in range(4)])[1:]), | |
'CHA': sum(sorted([random.randint(1, 6) for _ in range(4)])[1:]), | |
'HP': random.randint(1, 20) * 2 + random.randint(1, 20), | |
'MAX_HP': 40, | |
'score': 0, | |
'created_at': time.time() | |
} | |
def save_character_sheet(player_name, stats): | |
"""Save character sheet as markdown""" | |
filepath = f"characters/{player_name}.md" | |
os.makedirs('characters', exist_ok=True) | |
markdown = f"""# {player_name}'s Character Sheet | |
## Stats | |
- **STR**: {stats['STR']} | |
- **DEX**: {stats['DEX']} | |
- **CON**: {stats['CON']} | |
- **INT**: {stats['INT']} | |
- **WIS**: {stats['WIS']} | |
- **CHA**: {stats['CHA']} | |
## Health | |
HP: {stats['HP']}/{stats['MAX_HP']} | |
## Score | |
Current Score: {stats['score']} | |
## Position | |
X: {st.session_state.position['x']}, Y: {st.session_state.position['y']} | |
## Session Info | |
Created: {datetime.fromtimestamp(stats['created_at']).strftime('%Y-%m-%d %H:%M:%S')} | |
Last Updated: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')} | |
""" | |
with open(filepath, 'w') as f: | |
f.write(markdown) | |
def load_character_sheet(player_name): | |
"""Load character sheet if it exists""" | |
filepath = f"characters/{player_name}.md" | |
if os.path.exists(filepath): | |
with open(filepath, 'r') as f: | |
return f.read() | |
return None | |
def update_position(direction): | |
"""Update player position with wrapping""" | |
if direction == "up": | |
st.session_state.position['y'] = (st.session_state.position['y'] - 1) % GRID_HEIGHT | |
elif direction == "down": | |
st.session_state.position['y'] = (st.session_state.position['y'] + 1) % GRID_HEIGHT | |
elif direction == "left": | |
st.session_state.position['x'] = (st.session_state.position['x'] - 1) % GRID_WIDTH | |
elif direction == "right": | |
st.session_state.position['x'] = (st.session_state.position['x'] + 1) % GRID_WIDTH | |
st.session_state.last_move = time.time() | |
if st.session_state.character_stats: | |
save_character_sheet(st.session_state.player_name, st.session_state.character_stats) | |
def create_game_board(): | |
"""Create and display the game board""" | |
# Create placeholder images for tiles | |
tile_image = Image.new('RGB', (50, 50), color='green') | |
player_image = Image.new('RGB', (50, 50), color='blue') | |
# Create columns for each row | |
for y in range(GRID_HEIGHT): | |
cols = st.columns(GRID_WIDTH) | |
for x in range(GRID_WIDTH): | |
# Display player or tile | |
if (x == st.session_state.position['x'] and | |
y == st.session_state.position['y']): | |
cols[x].image(player_image, use_column_width=True) | |
else: | |
cols[x].image(tile_image, use_column_width=True) | |
def main(): | |
# Sidebar for player info and controls | |
st.sidebar.title("Player Info") | |
# Player name handling | |
if st.session_state.player_name is None: | |
default_name = generate_fantasy_name() | |
player_name = st.sidebar.text_input("Enter your name or use generated name:", | |
value=default_name) | |
if st.sidebar.button("Start Playing"): | |
st.session_state.player_name = player_name | |
if st.session_state.character_stats is None: | |
st.session_state.character_stats = roll_stats() | |
save_character_sheet(player_name, st.session_state.character_stats) | |
st.rerun() | |
else: | |
# Show current name and allow changes | |
new_name = st.sidebar.text_input("Your name:", | |
value=st.session_state.player_name) | |
if new_name != st.session_state.player_name: | |
old_name = st.session_state.player_name | |
st.session_state.player_name = new_name | |
os.rename(f"characters/{old_name}.md", | |
f"characters/{new_name}.md") | |
st.rerun() | |
# Display character sheet | |
character_sheet = load_character_sheet(st.session_state.player_name) | |
if character_sheet: | |
st.sidebar.markdown(character_sheet) | |
# Movement controls | |
st.sidebar.markdown("### Movement Controls") | |
move_cols = st.sidebar.columns(3) | |
if move_cols[1].button("⬆️", key="up"): | |
update_position("up") | |
st.rerun() | |
cols = st.sidebar.columns(3) | |
if cols[0].button("⬅️", key="left"): | |
update_position("left") | |
st.rerun() | |
if cols[1].button("⬇️", key="down"): | |
update_position("down") | |
st.rerun() | |
if cols[2].button("➡️", key="right"): | |
update_position("right") | |
st.rerun() | |
# Main game area | |
st.title("Multiplayer Tile Game") | |
# Display game board | |
create_game_board() | |
# Auto-refresh logic | |
if (time.time() - st.session_state.last_move) > REFRESH_RATE: | |
st.session_state.last_move = time.time() | |
st.rerun() | |
if __name__ == "__main__": | |
main() |