game_api.py 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. from flask import Blueprint, abort, request, jsonify
  2. import db
  3. import lib
  4. game = Blueprint("game", __name__)
  5. def require_game(game_id):
  6. g = db.Game.query.get(game_id)
  7. if g is None:
  8. abort(404)
  9. return g
  10. def require_player(game_id):
  11. auth = request.headers.get("Authorization", type=str)
  12. if auth is None:
  13. abort(401)
  14. try:
  15. pid = int(auth.split(maxsplit=1)[-1])
  16. except ValueError:
  17. abort(401)
  18. player = db.Player.query.get(pid)
  19. if player is None:
  20. abort(404)
  21. return player
  22. @game.route("", methods=["PUT"])
  23. def create_game():
  24. js = request.get_json()
  25. if js is None:
  26. abort(400)
  27. timer = js.get("timer", None)
  28. if not isinstance(timer, int) or timer <= 0:
  29. abort(400)
  30. rounds = js.get("rounds", None)
  31. if not isinstance(rounds, int) or rounds <= 0:
  32. abort(400)
  33. only_america = js.get("onlyAmerica", False)
  34. if not isinstance(only_america, bool):
  35. abort(400)
  36. new_game = db.Game.create(timer, rounds, only_america=only_america)
  37. return jsonify({"gameId": new_game.game_id})
  38. @game.route("/<game_id>")
  39. def game_settings(game_id):
  40. g = require_game(game_id)
  41. return jsonify(g.to_dict())
  42. @game.route("/<game_id>/config")
  43. def game_config(game_id):
  44. g = require_game(game_id)
  45. return jsonify({
  46. "timer": g.timer,
  47. "rounds": g.rounds,
  48. "onlyAmerica": g.only_america,
  49. })
  50. @game.route("/<game_id>/coords")
  51. def coords(game_id):
  52. g = require_game(game_id)
  53. return jsonify({
  54. str(c.round_number): {
  55. "lat": c.latitude,
  56. "lng": c.longitude,
  57. } for c in g.coordinates
  58. })
  59. @game.route("/<game_id>/players")
  60. def players(game_id):
  61. g = require_game(game_id)
  62. return jsonify({"players": [p.to_dict() for p in g.players]})
  63. @game.route("/<game_id>/linked", methods=["GET", "POST"])
  64. def link_game(game_id):
  65. g = require_game(game_id)
  66. if request.method == "GET":
  67. return jsonify({"linkedGame": g.linked_game})
  68. js = request.get_json()
  69. if js is None:
  70. abort(400)
  71. link_id = js.get("linkedGame", None)
  72. if link_id is None or db.Game.query.get(link_id) is None:
  73. abort(401)
  74. g.link(link_id)
  75. return "", 201
  76. @game.route("/<game_id>/join", methods=["POST"])
  77. def join(game_id):
  78. js = request.get_json()
  79. if js is None:
  80. abort(400)
  81. name = js.get("playerName", None)
  82. if name is None:
  83. abort(400)
  84. g = require_game(game_id)
  85. if db.Player.query.filter(db.Player.game_id == game_id, db.Player.player_name == name).first() is not None:
  86. abort(409)
  87. p = g.join(name)
  88. return jsonify({
  89. "playerId": str(p.player_id)
  90. }), 201
  91. @game.route("/<game_id>/current")
  92. def current_round(game_id):
  93. g = require_game(game_id)
  94. player = require_player(game_id)
  95. cur_rnd = player.get_current_round()
  96. if cur_rnd is None:
  97. coord = None
  98. else:
  99. lookup = db.Coordinate.query.get((game_id, cur_rnd))
  100. cur_rnd = str(cur_rnd)
  101. if lookup is None:
  102. coord = None
  103. else:
  104. coord = {
  105. "lat": lookup.latitude,
  106. "lng": lookup.longitude,
  107. }
  108. return jsonify({
  109. "currentRound": cur_rnd,
  110. "coord": coord,
  111. "timer": g.timer,
  112. })
  113. @game.route("/<game_id>/guesses/<int:round_num>", methods=["POST"])
  114. def make_guess(game_id, round_num):
  115. player = require_player(game_id)
  116. if round_num != player.get_current_round():
  117. abort(409)
  118. js = request.get_json()
  119. if js is None:
  120. abort(400)
  121. timed_out = js.get("timeout", False)
  122. if timed_out:
  123. player.add_timeout(round_num)
  124. db.session.commit()
  125. return jsonify({
  126. "score": 0,
  127. "totalScore": player.get_total_score(),
  128. "distance": None,
  129. }), 201
  130. try:
  131. lat = float(js.get("lat", None))
  132. lng = float(js.get("lng", None))
  133. remaining = int(js.get("timeRemaining", None))
  134. except ValueError:
  135. abort(400)
  136. target = db.Coordinate.query.get((game_id, round_num))
  137. if target is None:
  138. abort(400)
  139. guess_score, distance = lib.score((target.latitude, target.longitude), (lat, lng))
  140. player.add_guess(round_num, lat, lng, guess_score, remaining)
  141. return jsonify({
  142. "score": guess_score,
  143. "totalScore": player.get_total_score(),
  144. "distance": distance,
  145. }), 201