Spaces:
Running
Running
File size: 6,018 Bytes
60d0035 4877d4f 60d0035 308ea93 60d0035 4877d4f | 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 | import subprocess
import sys
# Ensure langgraph is installed at runtime (needed for HF Spaces environments)
subprocess.check_call([
sys.executable, "-m", "pip", "install",
"langgraph==0.2.28", "langchain-core>=0.2.0", "--quiet", "--no-warn-script-location"
])
import random
import gradio as gr
from typing_extensions import TypedDict
from langgraph.graph import StateGraph, START, END
# βββββββββββββββββββββββββββββββββββββββββ
# LangGraph Setup
# βββββββββββββββββββββββββββββββββββββββββ
class State(TypedDict):
bet: int
roll: int
game_state: str # "success" | "failure" | "pending"
def node_1(state: State) -> dict:
return {"game_state": "pending"}
def node_2(state: State) -> dict:
"""Success node."""
return {"game_state": "success"}
def node_3(state: State) -> dict:
"""Failure node."""
return {"game_state": "failure"}
def determine_outcome(state: State) -> str:
"""Route based on roll vs bet."""
return "node_2" if state["roll"] <= state["bet"] else "node_3"
# Build graph once at module load
builder = StateGraph(State)
builder.add_node("node_1", node_1)
builder.add_node("node_2", node_2)
builder.add_node("node_3", node_3)
builder.add_edge(START, "node_1")
builder.add_conditional_edges("node_1", determine_outcome)
builder.add_edge("node_2", END)
builder.add_edge("node_3", END)
graph = builder.compile()
# βββββββββββββββββββββββββββββββββββββββββ
# Gradio UI
# βββββββββββββββββββββββββββββββββββββββββ
STARTING_BALANCE = 100.0
with gr.Blocks(
title="π² LangGraph Dice Bet",
theme=gr.themes.Soft(primary_hue="violet"),
css="""
#title { text-align: center; }
#status_box { font-size: 1.1rem; text-align: center; min-height: 40px; }
#stop_btn { background: #ef4444 !important; color: white !important; }
""",
) as demo:
balance_state = gr.State(value=STARTING_BALANCE)
history_state = gr.State(value=[])
gr.Markdown("# π² LangGraph Dice Betting Game", elem_id="title")
gr.Markdown(
"Bet a number (1β12). Two dice are rolled β if the total is **β€ your bet** you win **$10**, "
"otherwise you lose **$5**. Starting balance: **$100**.",
elem_id="title",
)
with gr.Row():
balance_display = gr.Number(value=STARTING_BALANCE, label="π° Balance ($)", interactive=False)
wins_display = gr.Number(value=0, label="β
Wins", interactive=False)
losses_display = gr.Number(value=0, label="β Losses", interactive=False)
net_display = gr.Number(value=0.0, label="π Net P&L ($)", interactive=False)
gr.Markdown("---")
with gr.Row():
bet_input = gr.Slider(minimum=1, maximum=12, step=1, value=7, label="Your Bet (1β12)")
with gr.Column():
roll_btn = gr.Button("π² Roll!", variant="primary")
stop_btn = gr.Button("π Stop Playing", elem_id="stop_btn")
status_box = gr.Markdown("Place your bet and roll!", elem_id="status_box")
gr.Markdown("### π Round History")
history_box = gr.Dataframe(
headers=["Result"], datatype=["str"], value=[],
interactive=False, wrap=True,
)
stopped_msg = gr.Markdown(visible=False)
def on_roll(bet, balance, history, wins, losses):
bet = int(bet)
die1 = random.randint(1, 6)
die2 = random.randint(1, 6)
roll = die1 + die2
from concurrent.futures import ThreadPoolExecutor
with ThreadPoolExecutor(max_workers=1) as executor:
future = executor.submit(graph.invoke, {"bet": bet, "roll": roll, "game_state": "pending"})
result = future.result()
won = result["game_state"] == "success"
delta = 10 if won else -5
new_balance = balance + delta
new_wins = wins + (1 if won else 0)
new_losses = losses + (0 if won else 1)
net = new_balance - STARTING_BALANCE
emoji = "π WIN" if won else "π LOSS"
entry = f"{emoji} | Bet β€{bet} | Roll {die1}+{die2}={roll} | {'+ $10' if won else '- $5'} | Balance ${new_balance:.2f}"
new_history = [entry] + history
status = f"{'π’ WIN! +$10' if won else 'π΄ LOSS. -$5'} β rolled **{die1} + {die2} = {roll}** vs bet β€{bet}"
return (
new_balance, new_history, status,
new_wins, new_losses,
new_balance, new_wins, new_losses, round(net, 2),
[[r] for r in new_history],
gr.update(visible=False),
)
def on_stop(balance, wins, losses):
net = balance - STARTING_BALANCE
sign = "+ " if net >= 0 else ""
summary = (
f"### π Game Over!\n\n"
f"**Final Balance:** ${balance:.2f} | "
f"**Wins:** {int(wins)} | **Losses:** {int(losses)} | "
f"**Net P&L:** {sign}${net:.2f}"
)
return gr.update(value=summary, visible=True), gr.update(interactive=False), gr.update(interactive=False)
roll_btn.click(
fn=on_roll,
inputs=[bet_input, balance_state, history_state, wins_display, losses_display],
outputs=[
balance_state, history_state, status_box,
wins_display, losses_display,
balance_display, wins_display, losses_display, net_display,
history_box, stopped_msg,
],
)
stop_btn.click(
fn=on_stop,
inputs=[balance_state, wins_display, losses_display],
outputs=[stopped_msg, roll_btn, bet_input],
)
if __name__ == "__main__":
demo.launch() |