ftiiii commited on
Commit
4541f89
·
verified ·
1 Parent(s): 3878ee3

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +81 -10
app.py CHANGED
@@ -1,10 +1,11 @@
1
  import gradio as gr
2
  import random
3
 
 
4
  state = {
5
  "score_a": 0,
6
  "score_b": 0,
7
- "turn": "A",
8
  "round": 1,
9
  "total_rounds": 5
10
  }
@@ -32,7 +33,7 @@ def draw_scene(keeper_pos="giữa", ball_dir="giữa", is_goal=True, reset=False
32
  "phải": "translate(180px, -50px)"
33
  }[ball_dir]
34
 
35
- # Màu áo cầu thủ và số áo theo đội
36
  if state["turn"]=="A":
37
  shirt_color="#2196F3"
38
  pants_color="#1565C0"
@@ -48,8 +49,8 @@ def draw_scene(keeper_pos="giữa", ball_dir="giữa", is_goal=True, reset=False
48
  keeper_shirt="#FFFFFF"
49
  keeper_pants="#E0E0E0"
50
 
 
51
  if champion:
52
- # stickman nâng cúp
53
  html = f"""
54
  <div style="position:relative;width:100%;height:360px;background:linear-gradient(#4CAF50,#2e7d32);border-radius:20px;overflow:hidden;">
55
  <div style="position:absolute;bottom:30px;left:50%;transform:translateX(-50%);text-align:center;">
@@ -57,14 +58,14 @@ def draw_scene(keeper_pos="giữa", ball_dir="giữa", is_goal=True, reset=False
57
  <div style="width:20px;height:60px;background:gold;margin:auto;border-radius:4px 4px 0 0;position:relative;">
58
  <div style="width:40px;height:15px;background:gold;position:absolute;top:-15px;left:-10px;border-radius:50%;"></div>
59
  </div>
60
- <!-- Stickman -->
61
  <div style="position:relative;width:60px;height:120px;margin:auto;">
62
  <div style='width:18px;height:18px;background:#ffd1a4;border-radius:50%;position:absolute;top:0;left:50%;transform:translateX(-50%);'></div>
63
  <div style='width:6px;height:50px;background:{shirt_color};position:absolute;top:18px;left:50%;transform:translateX(-50%);'></div>
64
- <div style='width:6px;height:40px;background:{shirt_color};position:absolute;top:18px;left:0;transform:rotate(-60deg);transform-origin:top;'></div>
65
- <div style='width:6px;height:40px;background:{shirt_color};position:absolute;top:18px;right:0;transform:rotate(60deg);transform-origin:top;'></div>
66
- <div style='width:6px;height:40px;background:{pants_color};position:absolute;top:68px;left:20%;transform:rotate(20deg);'></div>
67
- <div style='width:6px;height:40px;background:{pants_color};position:absolute;top:68px;right:20%;transform:rotate(-20deg);'></div>
68
  <div style='position:absolute;top:30px;left:50%;transform:translateX(-50%);color:white;font-weight:bold;font-family:sans-serif;font-size:14px;'>{player_number}</div>
69
  </div>
70
  <div style="margin-top:5px;font-weight:bold;color:white;font-family:sans-serif;">{player_name} vô địch!</div>
@@ -90,7 +91,7 @@ def draw_scene(keeper_pos="giữa", ball_dir="giữa", is_goal=True, reset=False
90
  <!-- Cầu thủ -->
91
  <div style="position:absolute;bottom:30px;left:50%;transform:translateX(-50%);">
92
  <div style='width:18px;height:18px;background:#ffd1a4;border-radius:50%;margin:auto;'></div>
93
- <div style='width:6px;height:50px;background:{shirt_color};margin:auto;'></div>
94
  <div style='width:6px;height:40px;background:{shirt_color};position:absolute;top:18px;left:-10px;transform:rotate(20deg);'></div>
95
  <div style='width:6px;height:40px;background:{shirt_color};position:absolute;top:18px;right:-10px;transform:rotate(-20deg);'></div>
96
  <div style='width:6px;height:40px;background:{pants_color};position:absolute;top:68px;left:-10px;transform:rotate(20deg);'></div>
@@ -108,4 +109,74 @@ def draw_scene(keeper_pos="giữa", ball_dir="giữa", is_goal=True, reset=False
108
  </style>
109
  </div>
110
  """
111
- return html
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  import gradio as gr
2
  import random
3
 
4
+ # trạng thái game
5
  state = {
6
  "score_a": 0,
7
  "score_b": 0,
8
+ "turn": "A", # lượt đội A hoặc B
9
  "round": 1,
10
  "total_rounds": 5
11
  }
 
33
  "phải": "translate(180px, -50px)"
34
  }[ball_dir]
35
 
36
+ # màu áo cầu thủ và số áo theo đội
37
  if state["turn"]=="A":
38
  shirt_color="#2196F3"
39
  pants_color="#1565C0"
 
49
  keeper_shirt="#FFFFFF"
50
  keeper_pants="#E0E0E0"
51
 
52
+ # Nếu có champion: stickman nâng cúp
53
  if champion:
 
54
  html = f"""
55
  <div style="position:relative;width:100%;height:360px;background:linear-gradient(#4CAF50,#2e7d32);border-radius:20px;overflow:hidden;">
56
  <div style="position:absolute;bottom:30px;left:50%;transform:translateX(-50%);text-align:center;">
 
58
  <div style="width:20px;height:60px;background:gold;margin:auto;border-radius:4px 4px 0 0;position:relative;">
59
  <div style="width:40px;height:15px;background:gold;position:absolute;top:-15px;left:-10px;border-radius:50%;"></div>
60
  </div>
61
+ <!-- Stickman nâng cúp -->
62
  <div style="position:relative;width:60px;height:120px;margin:auto;">
63
  <div style='width:18px;height:18px;background:#ffd1a4;border-radius:50%;position:absolute;top:0;left:50%;transform:translateX(-50%);'></div>
64
  <div style='width:6px;height:50px;background:{shirt_color};position:absolute;top:18px;left:50%;transform:translateX(-50%);'></div>
65
+ <div style='width:6px;height:40px;background:{shirt_color};position:absolute;top:18px;left:-10px;transform:rotate(-60deg);'></div>
66
+ <div style='width:6px;height:40px;background:{shirt_color};position:absolute;top:18px;right:-10px;transform:rotate(60deg);'></div>
67
+ <div style='width:6px;height:40px;background:{pants_color};position:absolute;top:68px;left:15%;transform:rotate(20deg);'></div>
68
+ <div style='width:6px;height:40px;background:{pants_color};position:absolute;top:68px;right:15%;transform:rotate(-20deg);'></div>
69
  <div style='position:absolute;top:30px;left:50%;transform:translateX(-50%);color:white;font-weight:bold;font-family:sans-serif;font-size:14px;'>{player_number}</div>
70
  </div>
71
  <div style="margin-top:5px;font-weight:bold;color:white;font-family:sans-serif;">{player_name} vô địch!</div>
 
91
  <!-- Cầu thủ -->
92
  <div style="position:absolute;bottom:30px;left:50%;transform:translateX(-50%);">
93
  <div style='width:18px;height:18px;background:#ffd1a4;border-radius:50%;margin:auto;'></div>
94
+ <div style='width:6px;height:50px;background:{shirt_color};position:absolute;top:18px;left:50%;transform:translateX(-50%);'></div>
95
  <div style='width:6px;height:40px;background:{shirt_color};position:absolute;top:18px;left:-10px;transform:rotate(20deg);'></div>
96
  <div style='width:6px;height:40px;background:{shirt_color};position:absolute;top:18px;right:-10px;transform:rotate(-20deg);'></div>
97
  <div style='width:6px;height:40px;background:{pants_color};position:absolute;top:68px;left:-10px;transform:rotate(20deg);'></div>
 
109
  </style>
110
  </div>
111
  """
112
+ return html
113
+
114
+ # Sút penalty
115
+ def shoot_penalty(direction):
116
+ keeper = random.choice(["trái","giữa","phải"])
117
+ hit = direction != keeper
118
+ return keeper, hit
119
+
120
+ # xử lý lượt đá
121
+ def next_turn(direction):
122
+ keeper, hit = shoot_penalty(direction)
123
+ if state["turn"]=="A" and hit: state["score_a"] +=1
124
+ if state["turn"]=="B" and hit: state["score_b"] +=1
125
+ msg = f"Đội {state['turn']} sút {direction}, thủ môn đoán {keeper} → "
126
+ msg += "⚽ Bàn thắng!" if hit else "🧤 Cản phá, bóng dính thủ môn!"
127
+ scene = draw_scene(keeper, direction, hit)
128
+ return msg, scene
129
+
130
+ # Chuẩn bị lượt tiếp theo
131
+ def prepare_next_turn():
132
+ state["turn"] = "B" if state["turn"]=="A" else "A"
133
+ if state["turn"]=="A":
134
+ state["round"] +=1
135
+
136
+ # kiểm tra kết thúc
137
+ if state["round"] > state["total_rounds"]:
138
+ if state["score_a"] > state["score_b"]:
139
+ scene = draw_scene(champion="A")
140
+ msg_end = f"🏆 Đội A thắng {state['score_a']} - {state['score_b']}!"
141
+ elif state["score_b"] > state["score_a"]:
142
+ scene = draw_scene(champion="B")
143
+ msg_end = f"🏆 Đội B thắng {state['score_b']} - {state['score_a']}!"
144
+ else:
145
+ scene = draw_scene(champion="A") # đội A mặc định nâng cúp khi hòa
146
+ msg_end = f"🤝 Hòa {state['score_a']} - {state['score_b']}!"
147
+ score_text_val = f"**Điểm A: {state['score_a']} | Điểm B: {state['score_b']} | Lượt: 5/5**"
148
+ return score_text_val, scene, msg_end
149
+
150
+ scene_reset = draw_scene(reset=True)
151
+ score_text_val = f"**Điểm A: {state['score_a']} | Điểm B: {state['score_b']} | Lượt: {min(state['round'],5)}/5**"
152
+ return score_text_val, scene_reset, ""
153
+
154
+ # Reset game
155
+ def reset_game():
156
+ state.update({"score_a":0,"score_b":0,"turn":"A","round":1})
157
+ scene = draw_scene(reset=True)
158
+ return "**Điểm A: 0 | Điểm B: 0 | Lượt: 1/5**", scene, "Game mới bắt đầu! Đội A sút trước."
159
+
160
+ # Gradio interface
161
+ with gr.Blocks() as demo:
162
+ gr.Markdown("# ⚽ Penalty 2 Đội – 5 lượt + Stickman + Vô địch nâng cúp")
163
+
164
+ score_text = gr.Markdown("**Điểm A: 0 | Điểm B: 0 | Lượt: 1/5**")
165
+ result = gr.Markdown("Chọn hướng sút 👇")
166
+ field = gr.HTML(draw_scene(reset=True))
167
+
168
+ with gr.Row():
169
+ btn_left = gr.Button("⬅️ Trái")
170
+ btn_center = gr.Button("⬆️ Giữa")
171
+ btn_right = gr.Button("➡️ Phải")
172
+ btn_next = gr.Button("➡️ Tiếp theo") # reset tư thế chuẩn bị lượt tiếp theo
173
+ btn_restart = gr.Button("🔄 Chơi lại")
174
+
175
+ # sự kiện
176
+ btn_left.click(lambda _: next_turn("trái"), inputs=None, outputs=[result, field])
177
+ btn_center.click(lambda _: next_turn("giữa"), inputs=None, outputs=[result, field])
178
+ btn_right.click(lambda _: next_turn("phải"), inputs=None, outputs=[result, field])
179
+ btn_next.click(lambda _: prepare_next_turn(), inputs=None, outputs=[score_text, field, result])
180
+ btn_restart.click(lambda _: reset_game(), inputs=None, outputs=[score_text, field, result])
181
+
182
+ demo.launch()