CoolFace
Apppublic

Pratheeksha003/RL-Environment

sourceHugging Faceupdated 6mo agoView on Hugging Face
0likes
app.py406 linesDownload Raw Back to root
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