awacke1's picture
Create app.py
f4c6091 verified
raw
history blame
9.2 kB
import streamlit as st
from datetime import datetime
# Initialize session state
if 'scores' not in st.session_state:
st.session_state.scores = []
# HTML/JS game code
GAME_HTML = '''
<!DOCTYPE html>
<html>
<head>
<style>
body { margin: 0; }
#game-container {
width: 100%;
height: 400px;
background: black;
position: relative;
overflow: hidden;
}
.lander {
width: 32px;
height: 32px;
position: absolute;
transform: translate(-50%, -50%);
}
.thrust-particle {
width: 4px;
height: 4px;
background: red;
position: absolute;
border-radius: 50%;
}
.flag {
width: 4px;
height: 24px;
background: yellow;
position: absolute;
bottom: 48px;
}
.hud {
position: absolute;
color: white;
padding: 16px;
font-family: sans-serif;
}
.controls {
position: absolute;
top: 16px;
right: 16px;
color: white;
font-family: sans-serif;
font-size: 14px;
}
.game-over {
position: absolute;
inset: 0;
background: rgba(0,0,0,0.7);
display: flex;
align-items: center;
justify-content: center;
color: white;
font-family: sans-serif;
text-align: center;
}
button {
background: #a855f7;
border: none;
color: white;
padding: 8px 16px;
margin-top: 16px;
cursor: pointer;
border-radius: 4px;
}
button:hover {
background: #9333ea;
}
</style>
</head>
<body>
<div id="game-container">
<div class="hud">
<div id="fuel">Fuel: 100%</div>
<div id="velocity">Velocity: 0 m/s</div>
<div id="score"></div>
</div>
<div class="controls">
<div>↑ - Thrust</div>
<div>← β†’ - Move</div>
<div>Land between flags</div>
</div>
</div>
<script>
class LunarLander {
constructor() {
this.container = document.getElementById('game-container');
this.position = { x: 200, y: 50 };
this.velocity = { x: 0, y: 0 };
this.fuel = 100;
this.gameState = 'playing';
this.thrust = false;
this.GRAVITY = 0.05;
this.THRUST = 0.15;
this.LANDING_SPEED = 3;
this.groundPoints = [
{x: 0, y: 380}, {x: 100, y: 360}, {x: 150, y: 370},
{x: 200, y: 350}, {x: 300, y: 350}, {x: 350, y: 370},
{x: 400, y: 360}, {x: 450, y: 380}, {x: 500, y: 370}
];
this.setupGame();
}
setupGame() {
this.createLander();
this.createFlags();
this.createGround();
this.setupControls();
this.gameLoop();
}
createLander() {
this.lander = document.createElement('div');
this.lander.className = 'lander';
this.lander.style.background = '#a855f7';
this.container.appendChild(this.lander);
}
createFlags() {
const flag1 = document.createElement('div');
flag1.className = 'flag';
flag1.style.left = '190px';
const flag2 = document.createElement('div');
flag2.className = 'flag';
flag2.style.left = '310px';
this.container.appendChild(flag1);
this.container.appendChild(flag2);
}
createGround() {
const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
svg.style.position = 'absolute';
svg.style.bottom = '0';
svg.style.width = '100%';
svg.style.height = '100%';
const path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
const d = `M${this.groundPoints.map(p => `${p.x} ${p.y}`).join(' L')}`;
path.setAttribute('d', d);
path.setAttribute('stroke', 'white');
path.setAttribute('fill', 'none');
path.setAttribute('stroke-width', '2');
svg.appendChild(path);
this.container.appendChild(svg);
}
setupControls() {
document.addEventListener('keydown', (e) => {
if (this.gameState !== 'playing' || this.fuel <= 0) return;
switch (e.key) {
case 'ArrowUp':
this.thrust = true;
this.velocity.y -= this.THRUST;
this.fuel = Math.max(0, this.fuel - 0.5);
this.updateThrust();
break;
case 'ArrowLeft':
this.velocity.x -= 0.1;
this.fuel = Math.max(0, this.fuel - 0.2);
break;
case 'ArrowRight':
this.velocity.x += 0.1;
this.fuel = Math.max(0, this.fuel - 0.2);
break;
}
});
document.addEventListener('keyup', (e) => {
if (e.key === 'ArrowUp') {
this.thrust = false;
this.updateThrust();
}
});
}
updateThrust() {
const particles = this.lander.querySelectorAll('.thrust-particle');
particles.forEach(p => p.remove());
if (this.thrust) {
for (let i = 0; i < 4; i++) {
const particle = document.createElement('div');
particle.className = 'thrust-particle';
particle.style.left = `${Math.random() * 8 - 4}px`;
particle.style.top = `${Math.random() * 8}px`;
this.lander.appendChild(particle);
}
}
}
endGame(won) {
this.gameState = won ? 'won' : 'crashed';
const score = Math.floor(this.fuel * 100);
const overlay = document.createElement('div');
overlay.className = 'game-over';
overlay.innerHTML = `
<div>
<h2>${won ? 'Landing Successful!' : 'Crashed!'}</h2>
<div>Score: ${score}</div>
<button onclick="restartGame()">Play Again</button>
</div>
`;
this.container.appendChild(overlay);
if (won) {
window.parent.postMessage({
type: 'score',
score: score
}, '*');
}
}
checkCollision() {
for (let i = 0; i < this.groundPoints.length - 1; i++) {
const p1 = this.groundPoints[i];
const p2 = this.groundPoints[i + 1];
if (this.position.x >= p1.x && this.position.x <= p2.x) {
const groundY = p1.y + ((p2.y - p1.y) * (this.position.x - p1.x)) / (p2.x - p1.x);
if (this.position.y >= groundY - 10) {
if (this.velocity.y < this.LANDING_SPEED * 1.5 &&
Math.abs(this.velocity.x) < 2 &&
this.position.x >= 190 &&
this.position.x <= 310) {
this.endGame(true);
} else {
this.endGame(false);
}
return true;
}
}
}
return false;
}
updateHUD() {
document.getElementById('fuel').textContent = `Fuel: ${Math.floor(this.fuel)}%`;
document.getElementById('velocity').textContent = `Velocity: ${Math.floor(this.velocity.y * 10)} m/s`;
}
gameLoop = () => {
if (this.gameState === 'playing') {
this.position.x += this.velocity.x;
this.position.y += this.velocity.y;
this.velocity.x *= 0.99;
this.velocity.y += this.GRAVITY;
this.lander.style.left = `${this.position.x}px`;
this.lander.style.top = `${this.position.y}px`;
this.updateHUD();
this.checkCollision();
}
requestAnimationFrame(this.gameLoop);
}
}
let game;
function startGame() {
game = new LunarLander();
}
function restartGame() {
document.getElementById('game-container').innerHTML = `
<div class="hud">
<div id="fuel">Fuel: 100%</div>
<div id="velocity">Velocity: 0 m/s</div>
<div id="score"></div>
</div>
<div class="controls">
<div>↑ - Thrust</div>
<div>← β†’ - Move</div>
<div>Land between flags</div>
</div>
`;
startGame();
}
startGame();
</script>
</body>
</html>
'''
def main():
st.title("Lunar Lander")
# Display game
st.components.v1.html(GAME_HTML, height=450)
# Handle score updates
st.markdown("""
<script>
window.addEventListener('message', function(e) {
if (e.data.type === 'score') {
window.Streamlit.setComponentValue(e.data.score);
}
});
</script>
""", unsafe_allow_html=True)
# Display leaderboard
if st.session_state.scores:
st.subheader("Top Scores")
for score in sorted(st.session_state.scores, key=lambda x: x['score'], reverse=True)[:10]:
st.write(f"Score: {score['score']} - {score['timestamp'].strftime('%H:%M:%S')}")
# Reset scores button
if st.button("Reset Scores"):
st.session_state.scores = []
st.experimental_rerun()
if __name__ == "__main__":
main()