import json import hra.config as config import hra.db as db from hra.util import hash_passwd from datetime import datetime from sqlalchemy import exc, update class DuplicitMakeStep(Exception): pass class TooEarlyStep(Exception): pass def game_step(game_id: int, by_user: bool = False): ses = db.get_session() ses.expire_all() game = ses.query(db.Game).filter_by(game_id=game_id).with_for_update().one_or_none() assert game is not None time = datetime.now() if game.working_on_next_state: ses.commit() raise DuplicitMakeStep() old_round_id = game.current_round new_round_id = old_round_id + 1 old_state = ses.query(db.State).filter_by(game_id=game.game_id, round=old_round_id).one_or_none() if by_user: if (datetime.now() - old_state.create_time).total_seconds() < 5: raise TooEarlyStep() game.working_on_next_state = True ses.commit() moves = [None for _ in range(game.teams_count)] points = [0 for _ in range(game.teams_count)] for i in ses.query(db.Move).filter_by(game_id=game.game_id, round=old_round_id).all(): moves[i.team_id] = i.get_move() points[i.team_id] = i.points ses.commit() x, add_points = game.get_logic().step(old_state.get_state(), moves, old_round_id) points = [a+b for a,b in zip(points, add_points)] new_state = db.State(game_id=game.game_id, round=new_round_id, state=db.new_big_data(x), create_time=time) ses.add(new_state) for i in range(game.teams_count): db_move = db.Move(team_id=i, game_id=game_id, round=new_round_id, points=points[i]) ses.add(db_move) ses.expire_all() game = ses.query(db.Game).filter_by(game_id=game_id).with_for_update().one_or_none() assert game is not None assert game.working_on_next_state game.current_round = new_round_id game.working_on_next_state = False ses.commit() def game_restore_broken(game_id: int) -> None: ses = db.get_session() ses.expire_all() game = ses.query(db.Game).filter_by(game_id=game_id).with_for_update().one_or_none() game.working_on_next_state = False ses.commit() def create_game(mode, teams_count, configuration={}, test_for=None, name=None, step_mode=db.StepMode.none): ses = db.get_session() g = db.Game(game_mode=mode, configuration=db.new_big_data(configuration), teams_count=teams_count, name=name, step_mode=step_mode) ses.add(g) ses.flush() g.lock() s = db.State(game_id=g.game_id, round=0, state=db.new_big_data(g.get_logic().zero_state()), create_time=datetime.now()) ses.add(s) if test_for is not None: for i in range(teams_count): t = db.Team(team_id=i, game_id=g.game_id, name=f"test_{i}", user_id=test_for.id) ses.add(t) else: for i in range(teams_count): t = db.Team(team_id=i, game_id=g.game_id, name="") ses.add(t) for i in range(teams_count): db_move = db.Move(team_id=i, game_id=g.game_id, round=0) ses.add(db_move) g.current_round = 0 g.working_on_next_state = False return g def create_test_game(user): mode = "occupy" teams_count = 4 configuration = { "teams_width": 2, "teams_height": 2, "width_per_team": 10, "height_per_team": 10, "born_per_round": [1], "initial_remaining_rounds": 1000, "spawn_price": 10, "last_spawn": 100, "hills": [ ".xx....x..", ".xxx...xx.", "...x......", ".......xx.", ".......xx.", ".......x..", "..........", "..........", "..........", "..........", ], } return create_game(mode=mode, teams_count=teams_count, configuration=configuration, test_for=user, name=f"Testovací hra uživatele {user.username}", step_mode=db.StepMode.user) class UsernameExist(Exception): pass def create_user(username, passwd, org=False, test_game=True): u = db.User(org=org, username=username, passwd=hash_passwd(passwd)) u.gen_token() try: db.get_session().add(u) db.get_session().flush() except exc.IntegrityError: raise UsernameExist() if test_game: create_test_game(u) return u