new file: .env.example
new file: .gitignore new file: Dockerfile new file: README.md new file: app.py new file: app/__init__.py new file: app/game.py new file: app/models.py new file: app/routes.py new file: app/seed.py new file: data/movies.json new file: docker-compose.yml new file: requirements.txt new file: static/css/style.css new file: static/js/game.js new file: static/js/player.js new file: templates/index.html
This commit is contained in:
226
app/routes.py
Normal file
226
app/routes.py
Normal file
@@ -0,0 +1,226 @@
|
||||
from flask import Blueprint, jsonify, render_template, request
|
||||
|
||||
from . import db
|
||||
from .game import (
|
||||
_game_date, compare, daily_target, existing_daily_session, finish_session,
|
||||
get_max_attempts, get_or_create_player, get_streaks, is_correct, random_target,
|
||||
)
|
||||
from .models import Movie, Player, Session
|
||||
|
||||
bp = Blueprint("main", __name__)
|
||||
|
||||
|
||||
# ---------- Seiten ----------
|
||||
|
||||
@bp.route("/")
|
||||
def index():
|
||||
return render_template("index.html", mode="daily")
|
||||
|
||||
|
||||
@bp.route("/unlimited")
|
||||
def unlimited():
|
||||
return render_template("index.html", mode="unlimited")
|
||||
|
||||
|
||||
# ---------- API ----------
|
||||
|
||||
@bp.route("/api/player", methods=["POST"])
|
||||
def api_player():
|
||||
data = request.get_json(silent=True) or {}
|
||||
nickname = (data.get("nickname") or "").strip()
|
||||
if not nickname:
|
||||
return jsonify({"error": "nickname required"}), 400
|
||||
player = get_or_create_player(nickname)
|
||||
return jsonify({
|
||||
"player": {"id": player.id, "nickname": player.nickname},
|
||||
"streaks": get_streaks(player.id),
|
||||
})
|
||||
|
||||
|
||||
@bp.route("/api/search")
|
||||
def api_search():
|
||||
q = (request.args.get("q") or "").strip().lower()
|
||||
if not q:
|
||||
return jsonify([])
|
||||
movies = Movie.query.filter(Movie.title.ilike(f"%{q}%")).limit(10).all()
|
||||
return jsonify([
|
||||
{"id": m.id, "title": m.title, "year": m.year}
|
||||
for m in movies
|
||||
])
|
||||
|
||||
|
||||
@bp.route("/api/start", methods=["POST"])
|
||||
def api_start():
|
||||
data = request.get_json(silent=True) or {}
|
||||
player_id = data.get("player_id")
|
||||
mode = data.get("mode", "daily")
|
||||
if not player_id:
|
||||
return jsonify({"error": "player_id required"}), 400
|
||||
if Player.query.get(player_id) is None:
|
||||
return jsonify({"error": "player not found"}), 404
|
||||
if mode not in ("daily", "unlimited"):
|
||||
return jsonify({"error": "invalid mode"}), 400
|
||||
|
||||
max_attempts = get_max_attempts()
|
||||
|
||||
if mode == "daily":
|
||||
game_date = _game_date()
|
||||
target = daily_target(game_date)
|
||||
# Bereits heute gespielt?
|
||||
existing = existing_daily_session(player_id, game_date)
|
||||
if existing and existing.status != "in_progress":
|
||||
return jsonify({
|
||||
"session_id": existing.id,
|
||||
"mode": mode,
|
||||
"max_attempts": max_attempts,
|
||||
"status": existing.status,
|
||||
"already_played": True,
|
||||
"target": _movie_public(target),
|
||||
"attempts_used": existing.attempts_used,
|
||||
})
|
||||
# In-progress Rueckgabe, sonst neue Runde
|
||||
if existing:
|
||||
return jsonify({
|
||||
"session_id": existing.id,
|
||||
"mode": mode,
|
||||
"max_attempts": max_attempts,
|
||||
"status": existing.status,
|
||||
"already_played": False,
|
||||
"attempts_used": existing.attempts_used,
|
||||
})
|
||||
session = Session(
|
||||
player_id=player_id, mode=mode, target_movie_id=target.id,
|
||||
status="in_progress", attempts_used=0, date=game_date,
|
||||
)
|
||||
db.session.add(session)
|
||||
db.session.commit()
|
||||
return jsonify({
|
||||
"session_id": session.id,
|
||||
"mode": mode,
|
||||
"max_attempts": max_attempts,
|
||||
"status": "in_progress",
|
||||
"already_played": False,
|
||||
"attempts_used": 0,
|
||||
})
|
||||
|
||||
# Unbegrenzt: neue Zufallsrunde
|
||||
target = random_target()
|
||||
if target is None:
|
||||
return jsonify({"error": "no movies"}), 500
|
||||
session = Session(
|
||||
player_id=player_id, mode="unlimited", target_movie_id=target.id,
|
||||
status="in_progress", attempts_used=0,
|
||||
)
|
||||
db.session.add(session)
|
||||
db.session.commit()
|
||||
return jsonify({
|
||||
"session_id": session.id,
|
||||
"mode": mode,
|
||||
"max_attempts": max_attempts,
|
||||
"status": "in_progress",
|
||||
"already_played": False,
|
||||
"attempts_used": 0,
|
||||
})
|
||||
|
||||
|
||||
@bp.route("/api/guess", methods=["POST"])
|
||||
def api_guess():
|
||||
data = request.get_json(silent=True) or {}
|
||||
session_id = data.get("session_id")
|
||||
movie_id = data.get("movie_id")
|
||||
if not session_id or not movie_id:
|
||||
return jsonify({"error": "session_id and movie_id required"}), 400
|
||||
|
||||
session = Session.query.get(session_id)
|
||||
if session is None:
|
||||
return jsonify({"error": "session not found"}), 404
|
||||
if session.status != "in_progress":
|
||||
return jsonify({"error": "session already finished", "status": session.status}), 409
|
||||
|
||||
guess = Movie.query.get(movie_id)
|
||||
if guess is None:
|
||||
return jsonify({"error": "movie not found"}), 404
|
||||
|
||||
target = Movie.query.get(session.target_movie_id)
|
||||
max_attempts = get_max_attempts()
|
||||
|
||||
compared = compare(guess, target)
|
||||
session.attempts_used += 1
|
||||
used = session.attempts_used
|
||||
finished = False
|
||||
status = "in_progress"
|
||||
won = False
|
||||
|
||||
if is_correct(compared):
|
||||
finish_session(session, True)
|
||||
finished = True
|
||||
won = True
|
||||
status = "won"
|
||||
elif used >= max_attempts:
|
||||
finish_session(session, False)
|
||||
finished = True
|
||||
won = False
|
||||
status = "lost"
|
||||
|
||||
response = {
|
||||
"session_id": session.id,
|
||||
"attempts_used": used,
|
||||
"max_attempts": max_attempts,
|
||||
"status": status,
|
||||
"finished": finished,
|
||||
"won": won,
|
||||
"row": compared,
|
||||
}
|
||||
if finished:
|
||||
response["target"] = _movie_public(target)
|
||||
response["streaks"] = get_streaks(session.player_id)
|
||||
return jsonify(response)
|
||||
|
||||
|
||||
@bp.route("/api/streaks", methods=["POST"])
|
||||
def api_streaks():
|
||||
data = request.get_json(silent=True) or {}
|
||||
player_id = data.get("player_id")
|
||||
if not player_id:
|
||||
return jsonify({"error": "player_id required"}), 400
|
||||
return jsonify(get_streaks(player_id) or {"error": "player not found"})
|
||||
|
||||
|
||||
@bp.route("/api/new-game", methods=["POST"])
|
||||
def api_new_game():
|
||||
"""Startet (fuer den Unbegrenzt-Modus) eine neue Zufallsrunde."""
|
||||
data = request.get_json(silent=True) or {}
|
||||
player_id = data.get("player_id")
|
||||
if not player_id or Player.query.get(player_id) is None:
|
||||
return jsonify({"error": "player not found"}), 404
|
||||
target = random_target()
|
||||
if target is None:
|
||||
return jsonify({"error": "no movies"}), 500
|
||||
session = Session(
|
||||
player_id=player_id, mode="unlimited", target_movie_id=target.id,
|
||||
status="in_progress", attempts_used=0,
|
||||
)
|
||||
db.session.add(session)
|
||||
db.session.commit()
|
||||
return jsonify({
|
||||
"session_id": session.id,
|
||||
"mode": "unlimited",
|
||||
"max_attempts": get_max_attempts(),
|
||||
"status": "in_progress",
|
||||
"attempts_used": 0,
|
||||
})
|
||||
|
||||
|
||||
def _movie_public(movie):
|
||||
return {
|
||||
"id": movie.id,
|
||||
"title": movie.title,
|
||||
"year": movie.year,
|
||||
"fsk": movie.fsk,
|
||||
"studio": movie.studio.name if movie.studio else None,
|
||||
"director": movie.director,
|
||||
"budget": movie.budget,
|
||||
"universe": movie.universe.name if movie.universe else None,
|
||||
"genres": [g.name for g in movie.genres],
|
||||
"platforms": [p.name for p in movie.platforms],
|
||||
}
|
||||
Reference in New Issue
Block a user