File size: 8,224 Bytes
2fb15db
 
 
 
 
b0a6ae6
6e7673f
2fb15db
 
 
 
 
 
b0a6ae6
 
2fb15db
 
 
 
 
 
b0a6ae6
 
2fb15db
 
 
 
 
 
6e7673f
2fb15db
 
 
 
 
 
 
 
 
 
 
 
 
 
b0a6ae6
2fb15db
 
b0a6ae6
 
 
 
6e7673f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
b0a6ae6
 
6e7673f
b0a6ae6
6e7673f
b0a6ae6
 
 
6e7673f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
b0a6ae6
6e7673f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
b0a6ae6
 
 
 
2fb15db
6e7673f
b0a6ae6
2fb15db
 
b0a6ae6
 
 
 
 
 
 
 
 
2fb15db
 
 
 
6e7673f
b0a6ae6
 
 
 
6e7673f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
b0a6ae6
 
 
 
 
 
6e7673f
 
 
 
 
 
 
 
 
2fb15db
 
 
 
 
b0a6ae6
 
 
2fb15db
 
 
 
 
 
6e7673f
2fb15db
 
 
 
 
 
b0a6ae6
 
 
6e7673f
2fb15db
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
import streamlit as st
import json
import random
import time
import os
from streamlit_javascript import st_javascript
from math import cos, sin, pi

# Constants
GRID_SIZE = 10
MAX_PLAYERS = 10
UPDATE_INTERVAL = 3
GAME_STATE_FILE = "game_state.json"
CELL_SIZE = 50
PLAYER_SIZE = 40

# Initialize session state
if "player_name" not in st.session_state:
    st.session_state.player_name = f"Player_{random.randint(1000, 9999)}"
if "selected_player" not in st.session_state:
    st.session_state.selected_player = None
if "player_color" not in st.session_state:
    st.session_state.player_color = f"#{random.randint(0, 0xFFFFFF):06x}"

# Function to load game state
def load_game_state():
    if os.path.exists(GAME_STATE_FILE):
        with open(GAME_STATE_FILE, "r") as f:
            return json.load(f)
    return {"players": {}, "obstacles": []}

# Function to save game state
def save_game_state(state):
    with open(GAME_STATE_FILE, "w") as f:
        json.dump(state, f)

# Function to update player position
def update_player_position(player_name, x, y):
    state = load_game_state()
    if player_name in state["players"]:
        state["players"][player_name]["x"] = x
        state["players"][player_name]["y"] = y
    else:
        if len(state["players"]) < MAX_PLAYERS:
            state["players"][player_name] = {"x": x, "y": y, "color": st.session_state.player_color}
    save_game_state(state)

# Function to generate SVG for the game board
def generate_svg(game_state):
    svg = f'<svg width="{GRID_SIZE * CELL_SIZE}" height="{GRID_SIZE * CELL_SIZE}" xmlns="http://www.w3.org/2000/svg">'
    
    # Define gradients
    svg += '''
    <defs>
        <linearGradient id="grid-gradient" x1="0%" y1="0%" x2="100%" y2="100%">
            <stop offset="0%" style="stop-color:#f0f0f0;stop-opacity:1" />
            <stop offset="100%" style="stop-color:#d0d0d0;stop-opacity:1" />
        </linearGradient>
        <radialGradient id="player-gradient" cx="50%" cy="50%" r="50%" fx="50%" fy="50%">
            <stop offset="0%" style="stop-color:#ffffff;stop-opacity:0.8" />
            <stop offset="100%" style="stop-color:#000000;stop-opacity:0.1" />
        </radialGradient>
    </defs>
    '''
    
    # Draw grid with gradient
    svg += f'<rect width="{GRID_SIZE * CELL_SIZE}" height="{GRID_SIZE * CELL_SIZE}" fill="url(#grid-gradient)" />'
    for i in range(GRID_SIZE):
        for j in range(GRID_SIZE):
            svg += f'<rect x="{i * CELL_SIZE}" y="{j * CELL_SIZE}" width="{CELL_SIZE}" height="{CELL_SIZE}" fill="none" stroke="#a0a0a0" stroke-width="1" />'
    
    # Draw players with complex shapes and animations
    for player, data in game_state["players"].items():
        x, y = data["x"] * CELL_SIZE + CELL_SIZE // 2, data["y"] * CELL_SIZE + CELL_SIZE // 2
        color = data.get("color", "#000000")
        player_id = f"player-{player}"
        
        # Create a group for the player
        svg += f'<g id="{player_id}">'
        
        # Player body (hexagon)
        points = " ".join([f"{x + PLAYER_SIZE // 2 * cos(i * pi / 3)},{y + PLAYER_SIZE // 2 * sin(i * pi / 3)}" for i in range(6)])
        svg += f'<polygon points="{points}" fill="{color}" stroke="black" stroke-width="2">'
        svg += f'<animate attributeName="transform" attributeType="XML" type="rotate" from="0 {x} {y}" to="360 {x} {y}" dur="10s" repeatCount="indefinite" />'
        svg += '</polygon>'
        
        # Player eye (circle)
        eye_x, eye_y = x + PLAYER_SIZE // 4, y - PLAYER_SIZE // 4
        svg += f'<circle cx="{eye_x}" cy="{eye_y}" r="{PLAYER_SIZE // 8}" fill="white" stroke="black" stroke-width="1">'
        svg += f'<animate attributeName="r" values="{PLAYER_SIZE // 8};{PLAYER_SIZE // 10};{PLAYER_SIZE // 8}" dur="3s" repeatCount="indefinite" />'
        svg += '</circle>'
        
        # Player name
        svg += f'<text x="{x}" y="{y + PLAYER_SIZE // 2 + 15}" text-anchor="middle" fill="black" font-size="12" font-weight="bold">{player[:3].upper()}</text>'
        
        # Movement animations
        svg += f'<animateTransform attributeName="transform" attributeType="XML" type="translate" from="0 0" to="0 0" dur="0.5s" repeatCount="1" />'
        
        svg += '</g>'
    
    # Draw obstacles
    for obstacle in game_state.get("obstacles", []):
        ox, oy = obstacle["x"] * CELL_SIZE, obstacle["y"] * CELL_SIZE
        svg += f'<rect x="{ox}" y="{oy}" width="{CELL_SIZE}" height="{CELL_SIZE}" fill="url(#player-gradient)" stroke="black" stroke-width="2">'
        svg += f'<animate attributeName="opacity" values="0.7;0.9;0.7" dur="{random.uniform(2,5)}s" repeatCount="indefinite" />'
        svg += '</rect>'
    
    svg += '</svg>'
    return svg

# Streamlit app
st.set_page_config(layout="wide", page_title="Multiplayer Grid Game")
st.title("Enhanced Multiplayer Grid Game")

# Display player name and allow updates
col1, col2 = st.columns([3, 1])
with col1:
    player_name = st.text_input("Your name", value=st.session_state.player_name)
    if player_name != st.session_state.player_name:
        st.session_state.player_name = player_name
        update_player_position(player_name, GRID_SIZE // 2, GRID_SIZE // 2)

with col2:
    st.color_picker("Choose your color", value=st.session_state.player_color, key="player_color")

# Create grid
grid = st.empty()

# JavaScript for smooth movement and player highlight
js_code = """
function movePlayer(playerId, fromX, fromY, toX, toY) {
    const player = document.getElementById(playerId);
    if (player) {
        const animation = player.querySelector('animateTransform');
        animation.setAttribute('from', `${fromX - toX} ${fromY - toY}`);
        animation.setAttribute('to', '0 0');
        animation.beginElement();
        
        // Update player position after animation
        setTimeout(() => {
            const transform = player.getAttribute('transform') || '';
            player.setAttribute('transform', transform + ` translate(${toX - fromX} ${toY - fromY})`);
        }, 500);
    }
}

function pulsePlayer(playerId) {
    const player = document.getElementById(playerId);
    if (player) {
        const polygon = player.querySelector('polygon');
        const originalColor = polygon.getAttribute('fill');
        polygon.setAttribute('fill', '#ff0000');
        setTimeout(() => polygon.setAttribute('fill', originalColor), 300);
    }
}
"""

st.components.v1.html(f"<script>{js_code}</script>", height=0)

# Initialize obstacles if not present
game_state = load_game_state()
if "obstacles" not in game_state:
    game_state["obstacles"] = [
        {"x": random.randint(0, GRID_SIZE-1), "y": random.randint(0, GRID_SIZE-1)}
        for _ in range(5)
    ]
    save_game_state(game_state)

# Main game loop
while True:
    # Load current game state
    game_state = load_game_state()
    
    # Generate and display SVG
    svg = generate_svg(game_state)
    grid.markdown(svg, unsafe_allow_html=True)
    
    # Handle player movement
    col1, col2 = st.columns(2)
    with col1:
        if st.button("Select Your Character"):
            st.session_state.selected_player = st.session_state.player_name
            st_javascript(f"pulsePlayer('player-{st.session_state.player_name}')")
    
    with col2:
        if st.session_state.selected_player:
            target_x = st.number_input("Target X", min_value=0, max_value=GRID_SIZE-1, value=GRID_SIZE//2)
            target_y = st.number_input("Target Y", min_value=0, max_value=GRID_SIZE-1, value=GRID_SIZE//2)
            if st.button("Move"):
                current_pos = game_state["players"].get(st.session_state.player_name, {"x": GRID_SIZE // 2, "y": GRID_SIZE // 2})
                from_x, from_y = current_pos["x"] * CELL_SIZE + CELL_SIZE // 2, current_pos["y"] * CELL_SIZE + CELL_SIZE // 2
                to_x, to_y = target_x * CELL_SIZE + CELL_SIZE // 2, target_y * CELL_SIZE + CELL_SIZE // 2
                st_javascript(f"movePlayer('player-{st.session_state.player_name}', {from_x}, {from_y}, {to_x}, {to_y})")
                update_player_position(st.session_state.player_name, target_x, target_y)
    
    # Wait for update interval
    time.sleep(UPDATE_INTERVAL)
    st.experimental_rerun()