def move(sid, turn, units): user = dbi().get_user(sid) player = dbi().get_player(user.id) process = GameProcess.get(player.game) if turn != process.turn or not turn: raise BadTurn("Not actual turn number") fields = ["posX", "posY", "destX", "destY", "attackX", "attackY"] actions = [] for u in units: check_fields(fields, u) pos = u["posX"], u["posY"] attack = u["attackX"], u["attackY"] dest = u["destX"], u["destY"] if pos not in process.previous_placements or process.previous_placements[pos].player != player.player_number: raise BreakRules('No unit in that cell') if attack != NO_TARGET and attack not in process.previous_placements: raise BreakRules("Can't attack dummy target") path = find_shortest_path(process.map, pos, dest) if path is None: raise BreakRules("Target cell is unreachable") if len(path) > process.get_unit(pos).MP: raise BreakRules("Not enough MP") actions += [Action(pos, dest, attack)] moved = set(a.pos for a in actions) actions += [Action(pos, pos, NO_TARGET) for pos in process.player_previous_placements[player.player_number] if pos not in moved] process.current_actions += actions process.turn_finished() return response_ok()
def uploadArmy(sid, armyName, factionName, armyUnits): user = dbi().get_user(sid) squads = prepareArmy(user, armyName, factionName, armyUnits) army = Army(armyName, user.id) dbi().add(army) dbi().add_all(UnitArmy(unit.id, army.id, count) for unit, count in squads.items()) return response_ok()
def launch(test, debug=False, verbose=False, interactive=False): random.seed(common.SEED) testname = os.path.splitext(os.path.normpath(test))[0] outname = testname + '.out' ansname = testname + '.ans' requests = load_json(test) try: oldout = sys.stdout with open(outname, 'w') as sys.stdout: for request in requests: print(parse_request(request)) finally: sys.stdout = oldout dbi().clear() result = compare(testname) if result != 'OK' or verbose or debug: print('Test {0} {1}'.format(os.path.normpath(test), result)) if debug or (interactive and result != 'OK'): print(open(outname).read()) if interactive and result != 'OK': ans = "" while ans not in ('y', 'yes', 'n', 'no', 'yea', 'nay'): ans = input('Replace answer with this output? (y/n) ').lower().strip() if ans[0] == 'y': if os.path.exists(ansname): os.remove(ansname) os.rename(outname, ansname)
def uploadMap(sid, name, terrain): dbi().check_sid(sid) for line in terrain: if not isinstance(line, str): raise BadMap("Field 'terrain' must consist of strings") if dbi().query(Map).filter_by(name=name).count(): raise BadMap('Map with such name already exists') if not (0 < len(terrain) < MAX_MAP_HEIGHT): raise BadMap('Map height must be in range 1..{0}'.format(MAX_MAP_HEIGHT)) if len(set(map(len, terrain))) != 1: raise BadMap('Lines in map must have the same width') width = len(terrain[0]) if not (0 < width < MAX_MAP_WIDTH): raise BadMap('Map width must be in range 1..{0}'.format(MAX_MAP_WIDTH)) terrain = ''.join(terrain) chars = set(terrain) if not chars < set('.x123456789'): raise BadMap('Bad character in map description') chars -= set('.x') players = len(chars) if players < 2: raise BadMap('There should be deploy spots at least for two players') if players != int(max(chars)): raise BadMap( 'Player numbers should be consecutive and should start from one') dbi().add(Map(name, terrain, width, players)) return response_ok()
def getPlayerNumber(sid, gameName): user = dbi().get_user(sid) game = dbi().get_game(gameName) if game.state != 'started': raise BadGame("Cann't obtain players numbers for not started game") player = dbi().query(Player).join(Game).filter(Player.game_id==game.id).filter(Player.user_id==user.id).one() return response_ok(player_number=player.player_number)
def isMapExists(sid, name): dbi().check_sid(sid) result = True try: dbi().get_map(name) except BadMap: result = False return response_ok(exists=result)
def deleteArmy(sid, armyName): user = dbi().get_user(sid) try: army = dbi().query(Army).filter_by(name=armyName, user_id=user.id).one() except sqlalchemy.orm.exc.NoResultFound: raise BadArmy('No army with that name') dbi().delete(army) return response_ok()
def getMapList(sid): dbi().check_sid(sid) maps = [{ 'name': map.name, 'players': map.players, 'width': map.width, 'height': int(len(map.terrain) / map.width), } for map in dbi().query(Map).all()] return response_ok(maps=maps)
def createGame(sid, gameName, playersCount, mapName, factionName, totalCost): user = dbi().get_user(sid) if playersCount < 2: raise BadGame('Number of players must be 2 or more') if playersCount > MAX_PLAYERS: raise BadGame('Too many players') check_len(gameName, MAX_NAME_LENGTH, 'Too long game name', BadGame) check_emptiness(gameName, 'Empty game name', BadGame) if dbi().query(Player)\ .join(Game)\ .filter(Player.user_id == user.id)\ .filter(Player.is_creator == True)\ .filter(Game.state != 'finished')\ .count(): raise AlreadyInGame('User is already playing') if dbi().query(Game)\ .filter_by(name=gameName)\ .filter(Game.state != 'finished')\ .count(): raise AlreadyExists('Game with the such name already exists') if totalCost < MIN_TOTAL_COST: raise BadGame( 'totalCost must be greater than or equal to {0}'.format( MIN_TOTAL_COST)) map_id = dbi().get_map(mapName).id faction_id = dbi().get_faction(factionName).id game = Game(gameName, playersCount, map_id, faction_id, totalCost) dbi().add(game) player = Player(user.id, game.id) player.is_creator = True dbi().add(player) return response_ok()
def getArmy(sid, armyName): user = dbi().get_user(sid) try: army = dbi().query(Army).filter_by(name=armyName, user_id=user.id).one() except sqlalchemy.orm.exc.NoResultFound: raise BadArmy('No army with that name') result = [ { 'name': squad.unit.name, 'count': squad.count, } for squad in army.unitArmy ] return response_ok(units=result, factionName=army.unitArmy[0].unit.faction.name)
def unregister(sid): user = dbi().get_user(sid) try: player = dbi().query(Player).join(Game)\ .filter(Player.user_id == user.id)\ .filter(Game.state != 'finished')\ .one() except sqlalchemy.orm.exc.NoResultFound: pass else: leaveGame(sid, player.game.name) dbi().delete(user) return response_ok()
def chooseArmy(sid, armyName): user = dbi().get_user(sid) try: player = dbi().query(Player).filter_by( user_id=user.id, state='in_lobby').one() except sqlalchemy.orm.exc.NoResultFound: raise NotInGame("Can't choose army, because you're not in game") army = dbi().get_army(armyName, user.id) total_cost = sum(squad.unit.cost * squad.count for squad in army.unitArmy) if total_cost > player.game.total_cost: raise BadArmy('Your army is too expensive') player.army = army dbi().commit() return response_ok()
def getChatHistory(sid, gameName, **opt): dbi().check_sid(sid) game = dbi().get_game(gameName) if 'since' in opt: messages = dbi().query(Message).filter_by(game_id=game.id).filter(Message.id > int(opt['since'])).all() else: messages = game.messages chat = [{ "id": msg.id, "username": msg.user.username, "message": msg.text, "time": str(msg.dateSent), } for msg in messages] return response_ok(chat=chat)
def register(username, password): if not username.replace('_', '').isalnum(): raise BadUsername('Incorrect username') check_len(username, MAX_NAME_LENGTH, 'Too long username', BadUsername) check_emptiness(password, 'Empty password', BadPassword) if not DEBUG: password = hashlib.md5(password.encode("utf-8")).hexdigest() try: user = dbi().query(User).filter_by(username=username).one() if user.password != password: raise BadPassword( "User already exists, but passwords don't match") except sqlalchemy.orm.exc.NoResultFound: user = User(username, password) dbi().add(user) return response_ok(sid=user.sid)
def getGamesList(sid): user = dbi().get_user(sid) games = [] for game in dbi().query(Game).filter(Game.state != 'finished'): rec = { "gameName": game.name, "mapName": game.map.name, "factionName": game.faction.name, "gameStatus": game.state, "playersCount": game.players_count, "connectedPlayersCount": dbi().query(Player).filter_by(game_id=game.id).count(), "totalCost": game.total_cost, } games.append(rec) return response_ok(games=games)
def getArmiesList(sid): user = dbi().get_user(sid) result = [ { 'name': army.name, 'cost': sum(squad.unit.cost * squad.count for squad in army.unitArmy), 'faction': army.unitArmy[0].unit.faction.name, } for army in user.armies ] return response_ok(armies=result)
def editArmy(sid, armyName, newArmyName, factionName, armyUnits): user = dbi().get_user(sid) try: army = dbi().query(Army).filter_by(name=armyName, user_id=user.id).one() except sqlalchemy.orm.exc.NoResultFound: raise BadArmy('No army with that name') if (armyName != newArmyName and dbi().query(Army).filter_by(name=newArmyName, user_id=user.id).count() ): raise BadArmy('Already have army with this name') squads = prepareArmy(user, newArmyName, factionName, armyUnits, False) dbi().delete(army) army = Army(newArmyName, user.id) dbi().add(army) dbi().add_all(UnitArmy(unit.id, army.id, count) for unit, count in squads.items()) return response_ok()
def leaveGame(sid, gameName): user = dbi().get_user(sid) game = dbi().get_game(gameName) player = dbi().get_player(user.id, game.id) if game.state == 'not_started': dbi().delete(player) else: player.state = 'left' if not dbi().query(Player).filter_by(game_id=game.id).filter(Player.state!='left').count(): GameProcess.game_finished(gameName) game.state = 'finished' dbi().commit() return response_ok()
def setPlayerStatus(sid, status): user = dbi().get_user(sid) if status not in ('ready', 'in_lobby'): raise BadPlayerStatus('Unknown player status') try: player = dbi().query(Player).filter_by(user_id=user.id)\ .filter(or_(Player.state=='in_lobby', Player.state=='ready'))\ .one() except sqlalchemy.orm.exc.NoResultFound: raise BadUser('User is not in lobby') player.state = status query = dbi().query(Player).join(Game).filter(Game.id==player.game_id) if player.game.players_count == query.filter(Player.state=='ready').count(): for index, p in enumerate(player.game.players, start=1): p.state = 'in_game' p.player_number = index player.game.state = 'started' GameProcess(player.game) dbi().commit() return response_ok()
def __init__(self, game): self.game = game self.map = game.map.to_list() self.games[game.name] = self self.faction = game.faction.name self.current_placements = {} self.player_current_placements = {} self.turn = 0 self.ready_players = 0 self.factions[self.faction] = {unit.name: unit for unit in game.faction.units} self.usernames = [rec[0] for rec in dbi().query(User.username).join(Player) .filter(Player.game_id==game.id).order_by(Player.player_number).all()]
def sendMessage(sid, text, gameName): user = dbi().get_user(sid) game = dbi().get_game(gameName) check_len(text, MAX_MESSAGE_LENGTH, 'Too long message', BadMessage) dbi().get_player(user.id, game.id) dbi().add(Message(user.id, game.id, text)) return response_ok()
def prepareArmy(user, armyName, factionName, armyUnits, new=True): dbi().check_faction(factionName) check_len(armyName, MAX_NAME_LENGTH, 'Too long army name', BadArmy) check_emptiness(armyName, 'Empty army name', BadArmy) if new and dbi().query(Army).filter_by(user_id=user.id, name=armyName).count(): raise BadArmy('You have army with such name') squads = {} for unit in armyUnits: if not (isinstance(unit, dict) and len(unit) == 2 and 'name' in unit and 'count' in unit ): raise BadArmy( "Each element of armyUnits must have fields 'name' and 'count'") name, count = unit['name'], unit['count'] unit = dbi().get_unit(name, factionName) if unit in squads: squads[unit] += count elif count: squads[unit] = count check_emptiness(squads, 'Empty army', BadArmy) return squads
def placeUnits(sid, units): user = dbi().get_user(sid) player = dbi().get_player(user.id) process = GameProcess.get(player.game) if process.turn: raise BadTurn("Unit placing allowed only on zero turn") store = { squad.unit.name: squad.count for squad in player.army.unitArmy } fields = ["name", "posX", "posY"] to_place = [] for u in units: check_fields(fields, u) height, width = process.get_map_dimensions() if not (0 <= u["posX"] < width and 0 <= u["posY"] < height): raise BadCommand("Outside the map limits") x, y, name = u["posX"], u["posY"], u["name"] if not store.get(name, 0): raise BadUnit("No such units in army") to_place += [(name, x, y, player.player_number)] store[name] -= 1 for placement in to_place: process.place_unit(*placement) process.placement_finished() return response_ok()
def joinGame(sid, gameName): user = dbi().get_user(sid) game = dbi().get_game(gameName) if dbi().query(Player).join(Game)\ .filter(Game.id == game.id)\ .count() == game.players_count: raise BadGame('Game is full') if game.state == 'started': raise BadGame('Game already started') if dbi().get_player(user.id, game.id, silent=True): raise AlreadyInGame('User is already playing') dbi().add(Player(user.id, game.id)) return response_ok()
def getGameState(name): game = dbi().get_game(name) process = GameProcess.get(game) if not process.turn: raise BadTurn("You can't request game status before everyone place their units") result = { process.get_username(player_number): { "player_number": player_number, "units": [ { "name": process.previous_placements[pos].unit, "HP": process.previous_placements[pos].HP, "X": pos[0], "Y": pos[1] } for pos in placements ] } for player_number, placements in process.player_previous_placements.items() } return response_ok(players=result, turnNumber=process.turn, players_count=len(result))
def uploadFaction(sid, factionName, units): dbi().check_sid(sid) check_len(factionName, MAX_NAME_LENGTH, 'Too long faction name', BadFaction) check_emptiness(factionName, 'Empty faction name', BadFaction) if dbi().query(Faction).filter_by(name=factionName).count(): raise BadFaction('Faction already exists') faction = Faction(factionName) dbi().add(faction) if not units: raise BadFaction('Empty faction') for unit in units: if len(unit) > len(UNIT_ATTRS): raise BadUnit('Too many unit attributes') for attr in UNIT_ATTRS: if attr not in unit: raise BadUnit( "Unit description must contain field '{0}'".format(attr)) attr_type = UNIT_ATTRS[attr] if not isinstance(unit[attr], attr_type): raise BadUnit("Field '{0}' must be {1}".format( attr, HUMAN_READABLE_TYPES[attr_type])) dbi().add_all(Unit(faction_id=faction.id, **unit) for unit in units) return response_ok()
def getFactionList(sid): dbi().check_sid(sid) factions = [{"faction": name} for name in dbi().query(Faction.name).all()] return response_ok(factions=factions)
def last_game_process_query(game, obj): return dbi().query(obj).filter_by(game_id=game.id).order_by(desc(GameProcess.turnNumber)).first()
def ready_players_query(process): return (dbi().query(User.id).select_from(reduce(join, [Turn, UnitArmy, Army, User])) .filter(Turn.gameProcess_id==process.id).distinct())
def getFaction(sid, factionName): dbi().check_sid(sid) faction = dbi().get_faction(factionName) units = [dict((attr, getattr(unit, attr)) for attr in UNIT_ATTRS) for unit in faction.units] return response_ok(unitList=units)