def from_replay(cls, savegame_file=None, player_intelligence=Intelligence.Human, opponent_intelligence=Intelligence.Network): if not savegame_file: savegame_file = max(glob.iglob('./replay/*/*.json'), key=os.path.getctime) controller = cls(View(), Sound()) savegame_document = json.loads(open(savegame_file).read()) controller.game = Game.from_log_document(savegame_document, player_intelligence, opponent_intelligence) controller.clear_move() if controller.game.is_turn_done(): controller.game.shift_turn() controller.game.gamestate.set_available_actions() player = controller.game.current_player() print("current player is", player.color, player.intelligence) if play_fanfare: controller.sound.play_fanfare() return controller
def test_get_expected_action(): game_document = json.loads(open("./tests/keep_replays/3.json").read()) game = Game.from_log_document(game_document) expected_action = server_library.get_expected_action( game_document, game.gamestate) assert expected_action == (11, "move_with_attack")
def calculate_ratings(): games = list(get_collection("games").find({}).sort("finished_at", 1)) debug_lines = [] ranking = {} for game_document in games: try: log_document = construct_log_document(game_document) game = Game.from_log_document(log_document) if game.gamestate.is_ended(): winner = game.current_player().profile loser = game.opponent_player().profile if winner not in ranking: ranking[winner] = [1000] if loser not in ranking: ranking[loser] = [1000] ranking_winner = ranking[winner][-1] ranking_loser = ranking[loser][-1] rating_difference = ranking_loser - ranking_winner # "skill_factor" is an expression I came up with. I'm not sure what it's really called. # Arpad Elo came up with the value 400. It means that a player with 400 higher rating # than another player has a 90% probability of winning. At a difference of 200 the # probability is 75% skill_factor = float(2000) expected_outcome_for_winner = 1 / ( 1 + pow(10, (rating_difference / skill_factor))) # The k value determines the volatility in the ratings. 32 is pretty high. It's what ICC uses # It means that the most points that can be won in one game is 32 k_value = 32 rating_points_won_and_lost = int( k_value * (1 - expected_outcome_for_winner)) # debug_line = str(game_document["created_at"]) + " " # debug_line += " (" + str(game_document["_id"]) + "): " + winner + " beat " + loser # debug_line += " (p: " + "{0:.2f}".format(expected_outcome_for_winner) + "). " # debug_line += winner + ": " + str(ranking_winner) # debug_line += " => " + str(ranking_winner + rating_points_won_and_lost) + ", " # debug_line += loser + ": " + str(ranking_loser) # debug_line += " => " + str(ranking_loser - rating_points_won_and_lost) # debug_lines.append(debug_line) ranking[winner].append(ranking_winner + rating_points_won_and_lost) ranking[loser].append(ranking_loser - rating_points_won_and_lost) except Exception: debug_lines.append( str(game_document["_id"]) + ": " + traceback.format_exc()) #for index, line in enumerate(debug_lines): # ranking["debug_{0:03d}".format(index)] = line return ranking
def do_action_post(game_id): games = get_collection("games") game_document = games.find_one({"_id": ObjectId(game_id)}) if not game_document: return { "Status": "Error", "Message": "Could not find game with id " + game_id } try: action_document = request.json except ValueError: return { "Status": "Error", "Message": "No JSON decoded. Request body: " + request.body.getvalue() } action_document["created_at"] = datetime.utcnow() log_document = construct_log_document(game_document) game = Game.from_log_document(log_document) validation_errors = validate_input(log_document, game.gamestate, action_document) if validation_errors: return validation_errors if action_document[ "type"] == "options" and "move_with_attack" in action_document: response_document = register_move_with_attack(action_document, game_id, game.gamestate) cache.set(game_id, datetime.utcnow().replace(microsecond=0)) return response_document elif action_document["type"] == "options" and "upgrade" in action_document: response_document = register_upgrade(action_document, game.gamestate, game_id) cache.set(game_id, datetime.utcnow().replace(microsecond=0)) return response_document # Initial validation is done with a non-shifted gamestate, because it is # easier to find expected action from that # The rest is done with the turn shifted (if relevant) if game.is_turn_done(): game.shift_turn() result = validate_action(game.gamestate, action_document) if isinstance(result, dict): return result else: action = result response_document = register_move_attack_ability(action_document, game_id, game.gamestate, action) cache.set(game_id, datetime.utcnow().replace(microsecond=0)) return response_document
def from_network(cls, player): client = Client(player) game_document = client.get_game() controller = cls(View(), Sound()) controller.game = Game.from_log_document(game_document, player) controller.client = client player = controller.game.current_player() print("current player is", player.color, player.intelligence, player.profile) controller.clear_move() controller.game.gamestate.set_available_actions() if play_fanfare: controller.sound.play_fanfare() return controller
def is_outcome_correct(test_document): game = Game.from_log_document(test_document) controller = Controller(View(), Sound()) controller.positions = read_positions(test_document["pre_positions"]) controller.game = game click_position = Position.from_string(test_document["click_position"]) if "outcome" in test_document: outcome = Outcome.from_document(test_document["outcome"]) controller.determine_outcome = partial(determine_outcome, outcome) if "end_at" in test_document: end_at = test_document["end_at"] controller.pick_end_at = partial(pick_end_at, end_at) if "upgrade_choice" in test_document: upgrade_choice = int(test_document["upgrade_choice"]) controller.pick_upgrade = partial(pick_upgrade, upgrade_choice) if "move_with_attack" in test_document: controller.ask_about_move_with_attack = partial(ask_about_move_with_attack, test_document["move_with_attack"]) controller.game.gamestate.set_available_actions() controller.game.save = save controller.add_log = add_log controller.left_click(click_position) actual_gamestate = controller.game.gamestate.to_document() expected_gamestate = Gamestate.from_document(test_document["post_gamestate"]).to_document() actual_positions = controller.positions expected_positions = read_positions(test_document["post_positions"]) return give_output(actual_gamestate, expected_gamestate, actual_positions, expected_positions)
def view(game_id): last_modified_cache = cache.get(game_id) if last_modified_cache: if_modified_since_header = request.get_header("If-Modified-Since") if if_modified_since_header: if_modified_since_tuple = parsedate(if_modified_since_header) if_modified_since_timestamp = mktime(if_modified_since_tuple) if_modified_since = datetime.fromtimestamp( if_modified_since_timestamp) if last_modified_cache <= if_modified_since: # If our latest update is earlier than the client's latest update, # let the client know that nothing new is afoot response.status = 304 return games = get_collection("games") game_document = games.find_one({"_id": ObjectId(game_id)}) if not game_document: return { "Status": "Error", "Message": "Could not find game with id " + game_id } log_document = construct_log_document(game_document) game = Game.from_log_document(log_document) number = get_expected_action(log_document, game.gamestate)[0] if number == log_document["action_count"]: # Action isn't completed yet log_document["action_count"] = number - 1 last_modified = log_document["last_modified"] if last_modified > datetime(1970, 1, 1): stamp = mktime(last_modified.timetuple()) formatted_time = format_date_time(stamp) response.set_header("Last-Modified", formatted_time) cache.set(game_id, last_modified.replace(microsecond=0)) return log_document