awacke1 commited on
Commit
f4c6091
·
verified ·
1 Parent(s): ce7da08

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +336 -0
app.py ADDED
@@ -0,0 +1,336 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ from datetime import datetime
3
+
4
+ # Initialize session state
5
+ if 'scores' not in st.session_state:
6
+ st.session_state.scores = []
7
+
8
+ # HTML/JS game code
9
+ GAME_HTML = '''
10
+ <!DOCTYPE html>
11
+ <html>
12
+ <head>
13
+ <style>
14
+ body { margin: 0; }
15
+ #game-container {
16
+ width: 100%;
17
+ height: 400px;
18
+ background: black;
19
+ position: relative;
20
+ overflow: hidden;
21
+ }
22
+ .lander {
23
+ width: 32px;
24
+ height: 32px;
25
+ position: absolute;
26
+ transform: translate(-50%, -50%);
27
+ }
28
+ .thrust-particle {
29
+ width: 4px;
30
+ height: 4px;
31
+ background: red;
32
+ position: absolute;
33
+ border-radius: 50%;
34
+ }
35
+ .flag {
36
+ width: 4px;
37
+ height: 24px;
38
+ background: yellow;
39
+ position: absolute;
40
+ bottom: 48px;
41
+ }
42
+ .hud {
43
+ position: absolute;
44
+ color: white;
45
+ padding: 16px;
46
+ font-family: sans-serif;
47
+ }
48
+ .controls {
49
+ position: absolute;
50
+ top: 16px;
51
+ right: 16px;
52
+ color: white;
53
+ font-family: sans-serif;
54
+ font-size: 14px;
55
+ }
56
+ .game-over {
57
+ position: absolute;
58
+ inset: 0;
59
+ background: rgba(0,0,0,0.7);
60
+ display: flex;
61
+ align-items: center;
62
+ justify-content: center;
63
+ color: white;
64
+ font-family: sans-serif;
65
+ text-align: center;
66
+ }
67
+ button {
68
+ background: #a855f7;
69
+ border: none;
70
+ color: white;
71
+ padding: 8px 16px;
72
+ margin-top: 16px;
73
+ cursor: pointer;
74
+ border-radius: 4px;
75
+ }
76
+ button:hover {
77
+ background: #9333ea;
78
+ }
79
+ </style>
80
+ </head>
81
+ <body>
82
+ <div id="game-container">
83
+ <div class="hud">
84
+ <div id="fuel">Fuel: 100%</div>
85
+ <div id="velocity">Velocity: 0 m/s</div>
86
+ <div id="score"></div>
87
+ </div>
88
+ <div class="controls">
89
+ <div>↑ - Thrust</div>
90
+ <div>← → - Move</div>
91
+ <div>Land between flags</div>
92
+ </div>
93
+ </div>
94
+
95
+ <script>
96
+ class LunarLander {
97
+ constructor() {
98
+ this.container = document.getElementById('game-container');
99
+ this.position = { x: 200, y: 50 };
100
+ this.velocity = { x: 0, y: 0 };
101
+ this.fuel = 100;
102
+ this.gameState = 'playing';
103
+ this.thrust = false;
104
+
105
+ this.GRAVITY = 0.05;
106
+ this.THRUST = 0.15;
107
+ this.LANDING_SPEED = 3;
108
+
109
+ this.groundPoints = [
110
+ {x: 0, y: 380}, {x: 100, y: 360}, {x: 150, y: 370},
111
+ {x: 200, y: 350}, {x: 300, y: 350}, {x: 350, y: 370},
112
+ {x: 400, y: 360}, {x: 450, y: 380}, {x: 500, y: 370}
113
+ ];
114
+
115
+ this.setupGame();
116
+ }
117
+
118
+ setupGame() {
119
+ this.createLander();
120
+ this.createFlags();
121
+ this.createGround();
122
+ this.setupControls();
123
+ this.gameLoop();
124
+ }
125
+
126
+ createLander() {
127
+ this.lander = document.createElement('div');
128
+ this.lander.className = 'lander';
129
+ this.lander.style.background = '#a855f7';
130
+ this.container.appendChild(this.lander);
131
+ }
132
+
133
+ createFlags() {
134
+ const flag1 = document.createElement('div');
135
+ flag1.className = 'flag';
136
+ flag1.style.left = '190px';
137
+
138
+ const flag2 = document.createElement('div');
139
+ flag2.className = 'flag';
140
+ flag2.style.left = '310px';
141
+
142
+ this.container.appendChild(flag1);
143
+ this.container.appendChild(flag2);
144
+ }
145
+
146
+ createGround() {
147
+ const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
148
+ svg.style.position = 'absolute';
149
+ svg.style.bottom = '0';
150
+ svg.style.width = '100%';
151
+ svg.style.height = '100%';
152
+
153
+ const path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
154
+ const d = `M${this.groundPoints.map(p => `${p.x} ${p.y}`).join(' L')}`;
155
+ path.setAttribute('d', d);
156
+ path.setAttribute('stroke', 'white');
157
+ path.setAttribute('fill', 'none');
158
+ path.setAttribute('stroke-width', '2');
159
+
160
+ svg.appendChild(path);
161
+ this.container.appendChild(svg);
162
+ }
163
+
164
+ setupControls() {
165
+ document.addEventListener('keydown', (e) => {
166
+ if (this.gameState !== 'playing' || this.fuel <= 0) return;
167
+
168
+ switch (e.key) {
169
+ case 'ArrowUp':
170
+ this.thrust = true;
171
+ this.velocity.y -= this.THRUST;
172
+ this.fuel = Math.max(0, this.fuel - 0.5);
173
+ this.updateThrust();
174
+ break;
175
+ case 'ArrowLeft':
176
+ this.velocity.x -= 0.1;
177
+ this.fuel = Math.max(0, this.fuel - 0.2);
178
+ break;
179
+ case 'ArrowRight':
180
+ this.velocity.x += 0.1;
181
+ this.fuel = Math.max(0, this.fuel - 0.2);
182
+ break;
183
+ }
184
+ });
185
+
186
+ document.addEventListener('keyup', (e) => {
187
+ if (e.key === 'ArrowUp') {
188
+ this.thrust = false;
189
+ this.updateThrust();
190
+ }
191
+ });
192
+ }
193
+
194
+ updateThrust() {
195
+ const particles = this.lander.querySelectorAll('.thrust-particle');
196
+ particles.forEach(p => p.remove());
197
+
198
+ if (this.thrust) {
199
+ for (let i = 0; i < 4; i++) {
200
+ const particle = document.createElement('div');
201
+ particle.className = 'thrust-particle';
202
+ particle.style.left = `${Math.random() * 8 - 4}px`;
203
+ particle.style.top = `${Math.random() * 8}px`;
204
+ this.lander.appendChild(particle);
205
+ }
206
+ }
207
+ }
208
+
209
+ endGame(won) {
210
+ this.gameState = won ? 'won' : 'crashed';
211
+ const score = Math.floor(this.fuel * 100);
212
+
213
+ const overlay = document.createElement('div');
214
+ overlay.className = 'game-over';
215
+ overlay.innerHTML = `
216
+ <div>
217
+ <h2>${won ? 'Landing Successful!' : 'Crashed!'}</h2>
218
+ <div>Score: ${score}</div>
219
+ <button onclick="restartGame()">Play Again</button>
220
+ </div>
221
+ `;
222
+ this.container.appendChild(overlay);
223
+
224
+ if (won) {
225
+ window.parent.postMessage({
226
+ type: 'score',
227
+ score: score
228
+ }, '*');
229
+ }
230
+ }
231
+
232
+ checkCollision() {
233
+ for (let i = 0; i < this.groundPoints.length - 1; i++) {
234
+ const p1 = this.groundPoints[i];
235
+ const p2 = this.groundPoints[i + 1];
236
+
237
+ if (this.position.x >= p1.x && this.position.x <= p2.x) {
238
+ const groundY = p1.y + ((p2.y - p1.y) * (this.position.x - p1.x)) / (p2.x - p1.x);
239
+
240
+ if (this.position.y >= groundY - 10) {
241
+ if (this.velocity.y < this.LANDING_SPEED * 1.5 &&
242
+ Math.abs(this.velocity.x) < 2 &&
243
+ this.position.x >= 190 &&
244
+ this.position.x <= 310) {
245
+ this.endGame(true);
246
+ } else {
247
+ this.endGame(false);
248
+ }
249
+ return true;
250
+ }
251
+ }
252
+ }
253
+ return false;
254
+ }
255
+
256
+ updateHUD() {
257
+ document.getElementById('fuel').textContent = `Fuel: ${Math.floor(this.fuel)}%`;
258
+ document.getElementById('velocity').textContent = `Velocity: ${Math.floor(this.velocity.y * 10)} m/s`;
259
+ }
260
+
261
+ gameLoop = () => {
262
+ if (this.gameState === 'playing') {
263
+ this.position.x += this.velocity.x;
264
+ this.position.y += this.velocity.y;
265
+
266
+ this.velocity.x *= 0.99;
267
+ this.velocity.y += this.GRAVITY;
268
+
269
+ this.lander.style.left = `${this.position.x}px`;
270
+ this.lander.style.top = `${this.position.y}px`;
271
+
272
+ this.updateHUD();
273
+ this.checkCollision();
274
+ }
275
+
276
+ requestAnimationFrame(this.gameLoop);
277
+ }
278
+ }
279
+
280
+ let game;
281
+ function startGame() {
282
+ game = new LunarLander();
283
+ }
284
+
285
+ function restartGame() {
286
+ document.getElementById('game-container').innerHTML = `
287
+ <div class="hud">
288
+ <div id="fuel">Fuel: 100%</div>
289
+ <div id="velocity">Velocity: 0 m/s</div>
290
+ <div id="score"></div>
291
+ </div>
292
+ <div class="controls">
293
+ <div>↑ - Thrust</div>
294
+ <div>← → - Move</div>
295
+ <div>Land between flags</div>
296
+ </div>
297
+ `;
298
+ startGame();
299
+ }
300
+
301
+ startGame();
302
+ </script>
303
+ </body>
304
+ </html>
305
+ '''
306
+
307
+ def main():
308
+ st.title("Lunar Lander")
309
+
310
+ # Display game
311
+ st.components.v1.html(GAME_HTML, height=450)
312
+
313
+ # Handle score updates
314
+ st.markdown("""
315
+ <script>
316
+ window.addEventListener('message', function(e) {
317
+ if (e.data.type === 'score') {
318
+ window.Streamlit.setComponentValue(e.data.score);
319
+ }
320
+ });
321
+ </script>
322
+ """, unsafe_allow_html=True)
323
+
324
+ # Display leaderboard
325
+ if st.session_state.scores:
326
+ st.subheader("Top Scores")
327
+ for score in sorted(st.session_state.scores, key=lambda x: x['score'], reverse=True)[:10]:
328
+ st.write(f"Score: {score['score']} - {score['timestamp'].strftime('%H:%M:%S')}")
329
+
330
+ # Reset scores button
331
+ if st.button("Reset Scores"):
332
+ st.session_state.scores = []
333
+ st.experimental_rerun()
334
+
335
+ if __name__ == "__main__":
336
+ main()