game_api.py 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. from functools import wraps
  2. import uuid
  3. from flask import Blueprint, abort, request, current_app, jsonify
  4. from db import db, Game, CoordSet, GuessSet
  5. from lib import generate_coord, score
  6. game = Blueprint("game", __name__)
  7. def require_name():
  8. name = request.headers.get("Authorization", type=str)
  9. if name is None:
  10. abort(401)
  11. return name.split(maxsplit=1)[-1]
  12. def require_game(game_id):
  13. g = Game.query.get(game_id)
  14. if g is None:
  15. abort(404)
  16. return g
  17. def require_guess_set(game_id):
  18. name = require_name()
  19. gs = GuessSet.query.get((game_id, name))
  20. if gs is None:
  21. abort(404)
  22. return gs
  23. @game.route("", methods=["PUT"])
  24. def create_game():
  25. name = require_name()
  26. timer = request.json.get("timer", None)
  27. if not isinstance(timer, int) or timer <= 0:
  28. abort(400)
  29. game_id = str(uuid.uuid4())
  30. while Game.query.get(game_id) is not None:
  31. # basically impossible collision, but let's be safe
  32. game_id = str(uuid.uuid4())
  33. key = current_app.config["GOOGLE_API_KEY"]
  34. cs = CoordSet()
  35. for round_num in "12345":
  36. coord = generate_coord(key)
  37. while coord is None:
  38. # very unlikely, but it is possible for generate_coord to fail
  39. coord = generate_coord(key)
  40. cs.set_coord(round_num, *coord)
  41. db.session.add(cs)
  42. db.session.commit()
  43. new_game = Game(
  44. game_id=game_id,
  45. timer=timer,
  46. creator=name,
  47. coord_set=cs
  48. )
  49. db.session.add(new_game)
  50. db.session.commit()
  51. gs = GuessSet(game_id=game_id, player_name=name, coord_set=CoordSet())
  52. db.session.add(gs)
  53. db.session.commit()
  54. return jsonify({
  55. "gameId": game_id
  56. })
  57. @game.route("/<game_id>")
  58. def game_settings(game_id):
  59. g = require_game(game_id)
  60. return jsonify({
  61. "gameId": g.game_id,
  62. "creator": g.creator,
  63. "timer": g.timer,
  64. "coords": g.coord_set.to_dict(),
  65. "players": sorted([
  66. {
  67. "name": gs.player_name,
  68. "currentRound": gs.get_current_round(),
  69. "totalScore": gs.get_total_score(),
  70. "guesses": gs.to_dict(),
  71. } for gs in g.guess_sets
  72. ], key=lambda x: x["totalScore"] or 0, reverse=True),
  73. })
  74. @game.route("/<game_id>/join", methods=["POST"])
  75. def join(game_id):
  76. name = require_name()
  77. g = require_game(game_id)
  78. if GuessSet.query.get((g.game_id, name)) is not None:
  79. abort(409)
  80. cs = CoordSet()
  81. db.session.add(cs)
  82. db.session.commit()
  83. gs = GuessSet(game_id=g.game_id, player_name=name, coord_set=cs)
  84. db.session.add(gs)
  85. db.session.commit()
  86. return "", 201
  87. @game.route("/<game_id>/guesses")
  88. def guesses(game_id):
  89. gs = require_guess_set(game_id)
  90. return jsonify({
  91. "currentRound": gs.get_current_round(),
  92. "guesses": gs.to_dict(),
  93. })
  94. @game.route("/<game_id>/guesses/<round_num>", methods=["POST"])
  95. def make_guess(game_id, round_num):
  96. gs = require_guess_set(game_id)
  97. if round_num != gs.get_current_round():
  98. abort(409)
  99. timed_out = request.json.get("timeout", False)
  100. if timed_out:
  101. gs.set_timed_out(round_num)
  102. db.session.commit()
  103. return jsonify({
  104. "score": 0,
  105. "totalScore": gs.get_total_score(),
  106. }), 201
  107. lat = request.json.get("lat", None)
  108. lng = request.json.get("lng", None)
  109. if not isinstance(lat, float) or not isinstance(lng, float):
  110. abort(400)
  111. target = require_game(game_id).coord_set.get_coord(round_num)
  112. guess_score = score(target, (lat, lng))
  113. gs.set_guess(round_num, lat, lng, guess_score)
  114. db.session.commit()
  115. return jsonify({
  116. "score": guess_score,
  117. "totalScore": gs.get_total_score(),
  118. }), 201