Pratheeksha003/RL-Environment
0
1import streamlit as st2import numpy as np3import random4import time5 6st.set_page_config(7 page_title="๐ฅ Fire Escape Simulator",8 layout="centered",9 initial_sidebar_state="expanded"10)11 12# โโโ Custom CSS โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ13st.markdown("""14<style>15@import url('https://fonts.googleapis.com/css2?family=Share+Tech+Mono&family=Orbitron:wght@700&display=swap');16 17html, body, [class*="css"] {18 font-family: 'Share Tech Mono', monospace;19 background-color: #0c0c0c;20 color: #e0e0d0;21}22 23h1 {24 font-family: 'Orbitron', monospace !important;25 color: #ff6a00 !important;26 letter-spacing: 4px;27 font-size: 1.5rem !important;28}29 30.stButton > button {31 font-family: 'Share Tech Mono', monospace;32 background: transparent;33 border: 1px solid #444;34 color: #aaa;35 letter-spacing: 1px;36 font-size: 12px;37 padding: 6px 18px;38 transition: all 0.15s;39}40.stButton > button:hover {41 border-color: #ff6a00;42 color: #ff6a00;43 background: rgba(255,106,0,0.08);44}45 46.stSelectbox > div > div {47 background: #111;48 border: 1px solid #333;49 color: #aaa;50 font-family: 'Share Tech Mono', monospace;51}52 53.stSlider > div {54 color: #aaa;55}56 57.metric-card {58 background: #111;59 border: 1px solid #222;60 border-radius: 4px;61 padding: 12px 16px;62 text-align: center;63 font-family: 'Share Tech Mono', monospace;64}65.metric-label {66 font-size: 10px;67 color: #555;68 letter-spacing: 2px;69 margin-bottom: 4px;70}71.metric-value {72 font-size: 22px;73 color: #e0e0d0;74 font-weight: bold;75}76 77.grid-container {78 display: grid;79 grid-template-columns: repeat(6, 72px);80 gap: 5px;81 margin: 16px 0;82}83.cell {84 width: 72px;85 height: 72px;86 border-radius: 5px;87 border: 1px solid #1e1e1e;88 background: #111;89 display: flex;90 align-items: center;91 justify-content: center;92 font-size: 28px;93 transition: background 0.2s;94}95.cell-agent { background: #0d2b45; border-color: #378ADD; }96.cell-fire { background: #2d0a00; border-color: #ff4422; }97.cell-goal { background: #0a1e0a; border-color: #639922; }98.cell-dead { background: #3d0000; border-color: #ff0000; }99 100.status-bar {101 padding: 8px 14px;102 border-radius: 3px;103 font-size: 12px;104 letter-spacing: 1px;105 border-left: 3px solid transparent;106 margin-bottom: 12px;107}108.status-idle { border-left-color:#333; background:#111; color:#555; }109.status-win { border-left-color:#639922; background:rgba(99,153,34,0.1); color:#97C459; }110.status-lose { border-left-color:#ff4422; background:rgba(255,68,34,0.1); color:#ff8866; }111.status-info { border-left-color:#378ADD; background:rgba(55,138,221,0.07); color:#85B7EB; }112 113.legend {114 display: flex;115 gap: 18px;116 flex-wrap: wrap;117 font-size: 10px;118 color: #555;119 margin-bottom: 14px;120 letter-spacing: 1px;121}122.legend-item { display: flex; align-items: center; gap: 5px; }123.legend-dot {124 width: 11px; height: 11px;125 border-radius: 2px;126 border: 1px solid;127 display: inline-block;128}129 130.kbd {131 display: inline-block;132 background: #1a1a1a;133 border: 1px solid #333;134 border-radius: 3px;135 padding: 1px 7px;136 font-size: 11px;137 color: #888;138 margin: 2px;139}140 141section[data-testid="stSidebar"] {142 background: #0e0e0e;143 border-right: 1px solid #1e1e1e;144}145</style>146""", unsafe_allow_html=True)147 148 149# โโโ Constants โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ150SIZE = 6151ACTIONS = [(-1,0),(1,0),(0,-1),(0,1)] # up, down, left, right152ALPHA, GAMMA, EPSILON = 0.7, 0.9, 0.3153TRAIN_EPISODES = 1500154ICONS = {"agent": "๐ง", "fire": "๐ฅ", "goal": "๐ช", "empty": "", "dead": "๐"}155 156 157# โโโ RL helpers โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ158def take_step(pos, action):159 x, y = pos160 dx, dy = ACTIONS[action]161 nx, ny = x + dx, y + dy162 return [nx, ny] if 0 <= nx < SIZE and 0 <= ny < SIZE else list(pos)163 164 165def spread_fire(fire):166 new = [list(f) for f in fire]167 for f in fire:168 if random.random() < 0.22:169 dx, dy = random.choice(ACTIONS)170 nx, ny = f[0] + dx, f[1] + dy171 if 0 <= nx < SIZE and 0 <= ny < SIZE and [nx, ny] not in new:172 new.append([nx, ny])173 return new174 175 176def in_fire(pos, fire):177 return list(pos) in fire178 179 180# โโโ Train Q-table (cached so it only runs once) โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ181@st.cache_resource182def train_q():183 Q = np.zeros((SIZE, SIZE, 4))184 for _ in range(TRAIN_EPISODES):185 agent = [0, 0]186 goal = [SIZE-1, SIZE-1]187 fire = [[2, 2], [2, 3]]188 for _ in range(50):189 x, y = agent190 a = (random.randint(0, 3) if random.random() < EPSILON191 else int(np.argmax(Q[x, y])))192 npos = take_step(agent, a)193 fire = spread_fire(fire)194 r = (100 if npos == goal else195 -100 if in_fire(npos, fire) else -1)196 nx, ny = npos197 Q[x, y, a] += ALPHA * (r + GAMMA * np.max(Q[nx, ny]) - Q[x, y, a])198 agent = npos199 if r != -1:200 break201 return Q202 203Q = train_q()204 205 206# โโโ Session state init โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ207def init_state():208 if "agent" not in st.session_state:209 st.session_state.agent = [0, 0]210 st.session_state.fire = [[2, 2], [2, 3]]211 st.session_state.goal = [SIZE-1, SIZE-1]212 st.session_state.score = 0213 st.session_state.steps = 0214 st.session_state.status = ("idle", "[ waiting โ find the exit ]")215 st.session_state.game_over = False216 217init_state()218 219 220# โโโ Sidebar โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ221with st.sidebar:222 st.markdown("### โ๏ธ SETTINGS")223 mode = st.selectbox("Mode", ["AI Auto", "Manual Play"], key="mode_select")224 speed = st.slider("AI Speed (ms)", 300, 1200, 600, step=100)225 st.markdown("---")226 227 if st.button("๐ Reset Game"):228 st.session_state.agent = [0, 0]229 st.session_state.fire = [[2, 2], [2, 3]]230 st.session_state.steps = 0231 st.session_state.game_over = False232 st.session_state.status = ("idle", "[ game reset ]")233 st.rerun()234 235 st.markdown("---")236 st.markdown("""237**HOW IT WORKS**238 239The AI uses **Q-Learning** (RL) trained over 1,500 episodes.240It learns to navigate from `[0,0]` to the exit `[5,5]`241while avoiding spreading fire.242 243**Reward structure:**244- Reach exit: `+100`245- Hit fire: `-100`246- Each step: `-1`247""")248 249 250# โโโ Title โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ251st.markdown("# ๐ฅ FIRE ESCAPE")252st.markdown('<p style="font-size:11px;color:#555;letter-spacing:3px;margin-top:-12px">AI REINFORCEMENT LEARNING SIMULATOR</p>', unsafe_allow_html=True)253 254 255# โโโ Stats row โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ256c1, c2 = st.columns(2)257with c1:258 st.markdown(f"""259 <div class="metric-card">260 <div class="metric-label">SCORE</div>261 <div class="metric-value">{st.session_state.score}</div>262 </div>""", unsafe_allow_html=True)263with c2:264 st.markdown(f"""265 <div class="metric-card">266 <div class="metric-label">STEPS</div>267 <div class="metric-value">{st.session_state.steps}</div>268 </div>""", unsafe_allow_html=True)269 270st.markdown("<br>", unsafe_allow_html=True)271 272 273# โโโ Legend โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ274st.markdown("""275<div class="legend">276 <div class="legend-item"><span class="legend-dot" style="background:#0d2b45;border-color:#378ADD"></span>agent</div>277 <div class="legend-item"><span class="legend-dot" style="background:#2d0a00;border-color:#ff4422"></span>fire</div>278 <div class="legend-item"><span class="legend-dot" style="background:#0a1e0a;border-color:#639922"></span>exit</div>279 <div class="legend-item"><span class="legend-dot" style="background:#111;border-color:#222"></span>empty</div>280</div>281""", unsafe_allow_html=True)282 283 284# โโโ Grid renderer โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ285def render_grid():286 agent = st.session_state.agent287 fire = st.session_state.fire288 goal = st.session_state.goal289 290 html = '<div class="grid-container">'291 for i in range(SIZE):292 for j in range(SIZE):293 is_agent = (agent == [i, j])294 is_fire = in_fire([i, j], fire)295 is_goal = (goal == [i, j])296 297 if is_agent and is_fire:298 css, icon = "cell cell-dead", ICONS["dead"]299 elif is_agent:300 css, icon = "cell cell-agent", ICONS["agent"]301 elif is_fire:302 css, icon = "cell cell-fire", ICONS["fire"]303 elif is_goal:304 css, icon = "cell cell-goal", ICONS["goal"]305 else:306 css, icon = "cell", ICONS["empty"]307 308 html += f'<div class="{css}">{icon}</div>'309 html += "</div>"310 st.markdown(html, unsafe_allow_html=True)311 312render_grid()313 314 315# โโโ Status bar โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ316stype, smsg = st.session_state.status317st.markdown(f'<div class="status-bar status-{stype}">{smsg}</div>', unsafe_allow_html=True)318 319 320# โโโ Manual play controls โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ321if mode == "Manual Play" and not st.session_state.game_over:322 st.markdown("**KEYBOARD / BUTTON CONTROLS**")323 _, col_up, _ = st.columns([1, 1, 1])324 with col_up:325 if st.button("โฌ๏ธ UP", use_container_width=True):326 st.session_state.agent = take_step(st.session_state.agent, 0)327 st.session_state.steps += 1328 329 col_l, col_d, col_r = st.columns(3)330 with col_l:331 if st.button("โฌ
๏ธ LEFT", use_container_width=True):332 st.session_state.agent = take_step(st.session_state.agent, 2)333 st.session_state.steps += 1334 with col_d:335 if st.button("โฌ๏ธ DOWN", use_container_width=True):336 st.session_state.agent = take_step(st.session_state.agent, 1)337 st.session_state.steps += 1338 with col_r:339 if st.button("โก๏ธ RIGHT", use_container_width=True):340 st.session_state.agent = take_step(st.session_state.agent, 3)341 st.session_state.steps += 1342 343 # Spread fire after every manual move344 st.session_state.fire = spread_fire(st.session_state.fire)345 346 st.markdown("""347 <p style="font-size:10px;color:#444;letter-spacing:1px;margin-top:6px">348 Use buttons above โ or press <span class="kbd">W A S D</span> / arrow keys349 (click anywhere on the page first to capture keyboard focus)350 </p>351 """, unsafe_allow_html=True)352 353 354# โโโ AI auto-move โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ355if mode == "AI Auto" and not st.session_state.game_over:356 x, y = st.session_state.agent357 a = (random.randint(0, 3) if random.random() < 0.12358 else int(np.argmax(Q[x, y])))359 new_pos = take_step(st.session_state.agent, a)360 if new_pos == st.session_state.agent: # stuck โ explore361 new_pos = take_step(st.session_state.agent, random.randint(0, 3))362 st.session_state.agent = new_pos363 st.session_state.fire = spread_fire(st.session_state.fire)364 st.session_state.steps += 1365 366 367# โโโ Win / Lose checks โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ368def check_state():369 agent = st.session_state.agent370 fire = st.session_state.fire371 goal = st.session_state.goal372 373 if agent == goal:374 st.session_state.score += 10375 st.session_state.status = ("win", "[ โ
ESCAPED! +10 pts โ resetting... ]")376 st.session_state.game_over = True377 return "win"378 379 if in_fire(agent, fire):380 st.session_state.score -= 5381 st.session_state.status = ("lose", "[ ๐ฅ BURNED! -5 pts โ resetting... ]")382 st.session_state.game_over = True383 return "lose"384 385 st.session_state.status = ("info", f"[ step {st.session_state.steps} โ navigating... ]")386 return "ok"387 388result = check_state()389 390 391# โโโ Auto-reset after win/lose โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ392if result in ("win", "lose"):393 time.sleep(1.5)394 st.session_state.agent = [0, 0]395 st.session_state.fire = [[2, 2], [2, 3]]396 st.session_state.steps = 0397 st.session_state.game_over = False398 st.session_state.status = ("idle", "[ new round โ find the exit ]")399 st.rerun()400 401 402# โโโ AI auto-refresh loop โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ403if mode == "AI Auto" and not st.session_state.game_over:404 time.sleep(speed / 1000)405 st.rerun()406 