From 19418b5611e17484682120ff11078f68c56ae2b3 Mon Sep 17 00:00:00 2001 From: evanofslack Date: Sat, 4 Feb 2023 05:30:56 -0500 Subject: [PATCH 1/7] return result structs from game and simulator, return list of winners from game --- pyminion/game.py | 103 +++++++++++++----- pyminion/result.py | 80 ++++++++++++++ pyminion/simulator.py | 45 ++++---- tests/test_core/test_game.py | 24 ++-- tests/test_players/test_bots/test_bot_game.py | 9 +- 5 files changed, 204 insertions(+), 57 deletions(-) create mode 100644 pyminion/result.py diff --git a/pyminion/game.py b/pyminion/game.py index 0eeaac3..fb359fa 100644 --- a/pyminion/game.py +++ b/pyminion/game.py @@ -8,6 +8,7 @@ from pyminion.expansions.base import (copper, curse, duchy, estate, gold, province, silver) from pyminion.players import Player +from pyminion.result import GameOutcome, GameResult, PlayerSummary logger = logging.getLogger() @@ -113,7 +114,8 @@ def _create_basic_piles(self) -> List[Pile]: def _create_kingdom_piles(self) -> List[Pile]: """ - Create the kingdom piles that vary from kingdom to kingdom. This should be 10 piles each with 10 cards. + Create the kingdom piles that vary from kingdom to kingdom. + This should be 10 piles each with 10 cards. """ PILE_LENGTH: int = 10 @@ -151,7 +153,9 @@ def _create_kingdom_piles(self) -> List[Pile]: def _create_supply(self) -> Supply: """ - Create a supply consisting of the basic cards avaliable in every kingdom as well as the kingdom specific cards. + Create a supply consisting of basic cards + avaliable in every kingdom as well + as the kingdom specific cards. """ @@ -199,53 +203,102 @@ def is_over(self) -> bool: return False - def play(self): + def play(self) -> GameResult: self.start() while True: for player in self.players: player.take_turn(self) if self.is_over(): - self.get_stats() - return + result = self.summerize_game() + logging.info(f"\n{result}") + return result - def get_winner(self) -> Optional[Player]: + def get_winners(self) -> List[Player]: """ The player with the most victory points wins. If the highest scores are tied at the end of the game, the tied player who has had the fewest turns wins the game. If the tied players have had the same number of turns, they tie. - Returns the winning player or None if there is a tie. + Returns a list of players. If there is a single player in + the list, that is the sole winner. If there are multiple players + in the list, they are have tied for first. """ + # if one player only, they win by default if len(self.players) == 1: - return self.players[0] + return [self.players[0]] + # temporarily set first player as winner high_score = self.players[0].get_victory_points() - winner = self.players[0] - tie = False + winners = [self.players[0]] + # iterate the rest of the players in the game for player in self.players[1:]: score = player.get_victory_points() + + # if this player scored more, + # mark them as winner and high score if score > high_score: high_score = score - winner = player + winners = [player] + # if scores are equal elif score == high_score: - if player.turns < winner.turns: - winner = player - tie = False - elif player.turns == winner.turns: - tie = True - return None if tie else winner - - def get_stats(self): - if winner := self.get_winner(): - logger.info(f"\n{winner} won in {winner.turns} turns!") - else: - logger.info(f"\nGame ended in a tie after {self.players[0].turns} turns") + + # players tie if number of turns is equal + if player.turns == winners[0].turns: + winners.append(player) + + # otherwise, player with fewer turns wins + elif player.turns < winners[0].turns: + winners = [player] + + # note + # we can compare to just the first player in winners, + # because if there were multiple players in winners + # they would have equal score and turns + + return winners + + def summerize_game(self) -> GameResult: + """ + Called at the end of the game, + this creates a summary of the game + + """ + + player_summaries = [] + winners = self.get_winners() for player in self.players: - logger.info( - f"\n\nPlayer: {player} \nScore: {player.get_victory_points()} \nDeck: {DeckCounter(player.get_all_cards())}" + + # player won + if player in winners and len(winners) == 1: + result = GameOutcome.win + + # player tied + elif player in winners: + result = GameOutcome.tie + + # player lost + else: + result = GameOutcome.loss + + summary = PlayerSummary( + player=player, + result=result, + score=player.get_victory_points(), + turns=player.turns, + shuffles=player.shuffles, + deck=DeckCounter(player.get_all_cards()), ) + player_summaries.append(summary) + + game_result = GameResult( + game=self, + turns=winners[0].turns, + winners=winners, + player_summaries=player_summaries, + ) + return game_result diff --git a/pyminion/result.py b/pyminion/result.py new file mode 100644 index 0000000..4443ea0 --- /dev/null +++ b/pyminion/result.py @@ -0,0 +1,80 @@ +from dataclasses import dataclass, field +from enum import Enum +from typing import TYPE_CHECKING, List + +if TYPE_CHECKING: + from pyminion.core import DeckCounter + from pyminion.game import Game + from pyminion.players import Player + + +class GameOutcome(Enum): + """ + player can either lose, tie, or win the game + + """ + + loss = -1 + tie = 0 + win = 1 + + +@dataclass +class PlayerSummary: + """ + holds summary of a player from a complete game + + """ + + player: "Player" + result: "GameOutcome" + score: int + turns: int + shuffles: int + deck: "DeckCounter" + + def __repr__(self): + player = f"Player: {self.player.player_id}" + result = f"Result: {self.result}" + score = f"Score: {self.score}" + turns = f"Turns: {self.turns}" + shuffles = f"Shuffles: {self.shuffles}" + deck = f"Deck: {self.deck}" + + return f"{player}\n{result}\n{score}\n{turns}\n{shuffles}\n{deck}" + + +@dataclass +class GameResult: + """ + holds summary of a complete game + + """ + + game: "Game" + winners: List["Player"] + turns: int + player_summaries: List[PlayerSummary] + + def __repr__(self): + if len(self.winners) == 1: + result = f"{self.winners[0]} won in {self.turns} turns" + else: + result = f"{[w for w in self.winners]} tied after {self.turns} turns" + + format_summaries = "" + for s in self.player_summaries: + format_summaries += f"\n\n{s}" + + return f"Game Result: {result}{format_summaries}" + + +@dataclass +class SimulatorResult: + """ + holds summary of game outcomes over a simulation + + """ + + iterations: int + game_results: List[GameResult] diff --git a/pyminion/simulator.py b/pyminion/simulator.py index b0ae802..fc32f67 100644 --- a/pyminion/simulator.py +++ b/pyminion/simulator.py @@ -5,6 +5,7 @@ from pyminion.bots.bot import Bot from pyminion.game import Game from pyminion.players import Human, Player +from pyminion.result import GameResult, SimulatorResult, SimulatorStats logger = logging.getLogger() @@ -30,26 +31,30 @@ class Simulator: def __init__(self, game: Game, iterations: int = 100): self.game = game self.iterations = iterations - self.winners: List[Union[Player, Human, Bot]] + self.results: List[GameResult] - def run(self) -> None: + def run(self) -> SimulatorStats: logger.info(f"Simulating {self.iterations} games...") - winners = [] - for i in range(self.iterations): + for _ in range(self.iterations): game = copy.copy((self.game)) - game.play() - winner = game.get_winner() - winners.append(winner if winner else "tie") - self.winners = winners - self.get_stats() - - def get_stats(self) -> None: - logger.info(f"\nSimulation of {self.iterations} games") - for player in self.game.players: - logger.info( - f"{player.player_id} wins: {get_percent(self.winners.count(player), self.iterations)}% ({self.winners.count(player)})" - ) - - logger.info( - f"Ties: {get_percent(self.winners.count('tie'), self.iterations)}% ({self.winners.count('tie')})\n" - ) + result = game.play() + self.results.append(result) + + return self.summerize_simulation() + + # self.get_stats() + + def summerize_simulation(self) -> SimulatorResult: + result = SimulatorResult(iterations=self.iterations, game_results=self.results) + return result + + # def get_stats(self) -> None: + # logger.info(f"\nSimulation of {self.iterations} games") + # for player in self.game.players: + # logger.info( + # f"{player.player_id} wins: {get_percent(self.winners.count(player), self.iterations)}% ({self.winners.count(player)})" + # ) + # + # logger.info( + # f"Ties: {get_percent(self.winners.count('tie'), self.iterations)}% ({self.winners.count('tie')})\n" + # ) diff --git a/tests/test_core/test_game.py b/tests/test_core/test_game.py index 8b0d528..16cf873 100644 --- a/tests/test_core/test_game.py +++ b/tests/test_core/test_game.py @@ -1,7 +1,9 @@ import pytest + from pyminion.core import Card, Supply, Trash from pyminion.exceptions import InvalidGameSetup, InvalidPlayerCount -from pyminion.expansions.base import base_set, duchy, estate, gold, province, smithy +from pyminion.expansions.base import (base_set, duchy, estate, gold, province, + smithy) from pyminion.game import Game from pyminion.players import Human @@ -86,7 +88,7 @@ def test_game_is_over_false(game: Game): def test_game_is_over_true_provinces(game: Game): # Single player game ony has 5 provinces - for i in range(4): + for _ in range(4): game.supply.gain_card(card=province) assert not game.is_over() game.supply.gain_card(card=province) @@ -94,13 +96,13 @@ def test_game_is_over_true_provinces(game: Game): def test_game_is_over_true_three_piles(game: Game): - for i in range(5): + for _ in range(5): game.supply.gain_card(card=estate) assert not game.is_over() - for i in range(5): + for _ in range(5): game.supply.gain_card(card=duchy) assert not game.is_over() - for i in range(29): + for _ in range(29): game.supply.gain_card(card=gold) assert not game.is_over() game.supply.gain_card(card=gold) @@ -108,14 +110,20 @@ def test_game_is_over_true_three_piles(game: Game): def test_game_tie(multiplayer_game: Game): - assert multiplayer_game.get_winner() is None + # if equal score and equal turns, players tie + assert multiplayer_game.get_winners() == [ + multiplayer_game.players[0], + multiplayer_game.players[1], + ] def test_game_win(multiplayer_game: Game): + # player with more points wins multiplayer_game.players[0].deck.add(estate) - assert multiplayer_game.get_winner() == multiplayer_game.players[0] + assert multiplayer_game.get_winners() == [multiplayer_game.players[0]] def test_game_win_turns(multiplayer_game: Game): + # if equal score, player with less turns wins multiplayer_game.players[1].turns += 1 - assert multiplayer_game.get_winner() == multiplayer_game.players[0] + assert multiplayer_game.get_winners() == [multiplayer_game.players[0]] diff --git a/tests/test_players/test_bots/test_bot_game.py b/tests/test_players/test_bots/test_bot_game.py index 55e3094..86aad7b 100644 --- a/tests/test_players/test_bots/test_bot_game.py +++ b/tests/test_players/test_bots/test_bot_game.py @@ -3,7 +3,8 @@ from pyminion.game import Game -def test_game_1_player_play(bm_bot: BigMoney): +def test_game_single_player_play(bm_bot: BigMoney): + # single player always wins by default game = Game( players=[bm_bot], expansions=[base_set], @@ -11,7 +12,7 @@ def test_game_1_player_play(bm_bot: BigMoney): use_logger=False, ) game.play() - assert game.get_winner() == bm_bot + assert game.get_winners() == [bm_bot] def test_game_2_player_play(bm_bot: BigMoney): @@ -22,7 +23,7 @@ def test_game_2_player_play(bm_bot: BigMoney): use_logger=False, ) game.play() - game.get_winner() + assert len(game.get_winners()) >= 1 def test_game_2_player_with_actions(): @@ -34,4 +35,4 @@ def test_game_2_player_with_actions(): use_logger=False, ) game.play() - game.get_winner() + assert len(game.get_winners()) >= 1 From e10c6b13441718a62e79bcdb78f56a7999a23ffb Mon Sep 17 00:00:00 2001 From: evanofslack Date: Sat, 4 Feb 2023 05:40:48 -0500 Subject: [PATCH 2/7] update examples --- examples/bot_game.py | 6 ++++-- examples/human_game.py | 17 ++++++++++++----- examples/simulation.py | 12 +++++++++--- 3 files changed, 25 insertions(+), 10 deletions(-) diff --git a/examples/bot_game.py b/examples/bot_game.py index 150b94e..2e2fc4c 100644 --- a/examples/bot_game.py +++ b/examples/bot_game.py @@ -1,5 +1,5 @@ """ -Run a single game between two bots. +Run a single game between two bots. """ @@ -15,7 +15,9 @@ players=[bm, bm_ultimate], expansions=[base_set], kingdom_cards=[smithy], + use_logger=True, + log_file_name="pyminion.log", ) if __name__ == "__main__": - game.play() + result = game.play() diff --git a/examples/human_game.py b/examples/human_game.py index 44c0800..9e1f7c3 100644 --- a/examples/human_game.py +++ b/examples/human_game.py @@ -1,16 +1,23 @@ """ -Play a game through the terminal. Either by yourself, with another human, or against a bot. +Play a game through the terminal. Either by yourself, with another human, or against a bot. """ + from pyminion.bots.examples import BigMoney -from pyminion.expansions.base import base_set +from pyminion.expansions.base import artisan, bandit, base_set, witch from pyminion.game import Game from pyminion.players import Human human = Human(player_id="Human") -bot = BigMoney(player_id="Bot 1") +bm = BigMoney(player_id="Big Moneu") -game = Game(players=[human, bot], expansions=[base_set]) +game = Game( + players=[human, bm], + expansions=[base_set], + kingdom_cards=[artisan, bandit, witch], + use_logger=True, + log_file_name="pyminion.log", +) if __name__ == "__main__": - game.play() + result = game.play() diff --git a/examples/simulation.py b/examples/simulation.py index c126584..949c442 100644 --- a/examples/simulation.py +++ b/examples/simulation.py @@ -1,5 +1,5 @@ """ -Simulate multiple games between two or more bots. +Simulate multiple games between two or more bots. """ from pyminion.bots.examples import BigMoney, BigMoneySmithy @@ -11,9 +11,15 @@ bm_smithy = BigMoneySmithy() -game = Game(players=[bm, bm_smithy], expansions=[base_set], kingdom_cards=[smithy]) +game = Game( + players=[bm, bm_smithy], + expansions=[base_set], + kingdom_cards=[smithy], + use_logger=False, +) sim = Simulator(game, iterations=1000) if __name__ == "__main__": - sim.run() + result = sim.run() + print(result) From 06d058dde9281c6f8e5f2a24516db5ac2c5e40c2 Mon Sep 17 00:00:00 2001 From: evanofslack Date: Sat, 4 Feb 2023 05:41:03 -0500 Subject: [PATCH 3/7] fix player shuffle count not being reset --- pyminion/players.py | 1 + pyminion/simulator.py | 10 ++++------ 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/pyminion/players.py b/pyminion/players.py index 4f593d2..0976f51 100644 --- a/pyminion/players.py +++ b/pyminion/players.py @@ -65,6 +65,7 @@ def reset(self): """ self.turns = 0 + self.shuffles = 0 self.deck.cards = [] self.discard_pile.cards = [] self.hand.cards = [] diff --git a/pyminion/simulator.py b/pyminion/simulator.py index fc32f67..d3cf276 100644 --- a/pyminion/simulator.py +++ b/pyminion/simulator.py @@ -1,11 +1,9 @@ import copy import logging -from typing import List, Union +from typing import List -from pyminion.bots.bot import Bot from pyminion.game import Game -from pyminion.players import Human, Player -from pyminion.result import GameResult, SimulatorResult, SimulatorStats +from pyminion.result import GameResult, SimulatorResult logger = logging.getLogger() @@ -31,9 +29,9 @@ class Simulator: def __init__(self, game: Game, iterations: int = 100): self.game = game self.iterations = iterations - self.results: List[GameResult] + self.results: List[GameResult] = [] - def run(self) -> SimulatorStats: + def run(self) -> SimulatorResult: logger.info(f"Simulating {self.iterations} games...") for _ in range(self.iterations): game = copy.copy((self.game)) From b34ca66f27793d915f95b5dbf42edfd4066c2528 Mon Sep 17 00:00:00 2001 From: evanofslack Date: Sat, 4 Feb 2023 23:10:31 -0500 Subject: [PATCH 4/7] update simulation result --- pyminion/result.py | 24 +++++++++++++++--- pyminion/simulator.py | 57 ++++++++++++++++++++++++++++++------------- 2 files changed, 61 insertions(+), 20 deletions(-) diff --git a/pyminion/result.py b/pyminion/result.py index 4443ea0..b3dcb31 100644 --- a/pyminion/result.py +++ b/pyminion/result.py @@ -27,7 +27,7 @@ class PlayerSummary: """ player: "Player" - result: "GameOutcome" + result: GameOutcome score: int turns: int shuffles: int @@ -35,7 +35,7 @@ class PlayerSummary: def __repr__(self): player = f"Player: {self.player.player_id}" - result = f"Result: {self.result}" + result = f"Result: {self.result.name}" score = f"Score: {self.score}" turns = f"Turns: {self.turns}" shuffles = f"Shuffles: {self.shuffles}" @@ -64,11 +64,19 @@ def __repr__(self): format_summaries = "" for s in self.player_summaries: - format_summaries += f"\n\n{s}" + format_summaries += f"\n{s}" return f"Game Result: {result}{format_summaries}" +@dataclass +class PlayerSimulatorResult: + player: "Player" + wins: int + losses: int + ties: int + + @dataclass class SimulatorResult: """ @@ -78,3 +86,13 @@ class SimulatorResult: iterations: int game_results: List[GameResult] + player_results: List[PlayerSimulatorResult] + + def __repr__(self): + title = f"ran {self.iterations} games" + + format_results = "" + for result in self.player_results: + format_results += f"\n{result.player.player_id} won {result.wins}, lost {result.losses}, tied {result.ties}" + + return f"Simulation Result: {title}{format_results}" diff --git a/pyminion/simulator.py b/pyminion/simulator.py index d3cf276..79dcd07 100644 --- a/pyminion/simulator.py +++ b/pyminion/simulator.py @@ -1,9 +1,10 @@ import copy import logging -from typing import List +from typing import Dict, List from pyminion.game import Game -from pyminion.result import GameResult, SimulatorResult +from pyminion.players import Player +from pyminion.result import GameResult, PlayerSimulatorResult, SimulatorResult logger = logging.getLogger() @@ -38,21 +39,43 @@ def run(self) -> SimulatorResult: result = game.play() self.results.append(result) - return self.summerize_simulation() + return self.get_sim_result() - # self.get_stats() + def get_sim_result(self) -> SimulatorResult: - def summerize_simulation(self) -> SimulatorResult: - result = SimulatorResult(iterations=self.iterations, game_results=self.results) - return result + # make temp hashmap to store player sim results + player_results: Dict[Player, PlayerSimulatorResult] = {} - # def get_stats(self) -> None: - # logger.info(f"\nSimulation of {self.iterations} games") - # for player in self.game.players: - # logger.info( - # f"{player.player_id} wins: {get_percent(self.winners.count(player), self.iterations)}% ({self.winners.count(player)})" - # ) - # - # logger.info( - # f"Ties: {get_percent(self.winners.count('tie'), self.iterations)}% ({self.winners.count('tie')})\n" - # ) + # initialize each player result with default values + for player in self.game.players: + player_results[player] = PlayerSimulatorResult( + player=player, wins=0, losses=0, ties=0 + ) + + # iterate through each simulated game to determine win record + for result in self.results: + + # single player wins + if len(result.winners) == 1: + player_results[result.winners[0]].wins += 1 + + # multiple players tie + else: + for player in result.winners: + player_results[player].ties += 1 + + # rest of players are losers + for player in self.game.players: + if player not in result.winners: + player_results[player].losses += 1 + + player_results_final: List[PlayerSimulatorResult] = list( + player_results.values() + ) + + sim_result = SimulatorResult( + iterations=self.iterations, + game_results=self.results, + player_results=player_results_final, + ) + return sim_result From df39e0b0ec9c5b4e575b6b9a8f1a8a1ff9a6b5fd Mon Sep 17 00:00:00 2001 From: evanofslack Date: Sun, 5 Feb 2023 00:18:27 -0500 Subject: [PATCH 5/7] add option to not log game to stdout --- pyminion/__init__.py | 19 ++++--------------- pyminion/game.py | 16 +++++++++++++--- 2 files changed, 17 insertions(+), 18 deletions(-) diff --git a/pyminion/__init__.py b/pyminion/__init__.py index 0c48ae5..c6dff60 100644 --- a/pyminion/__init__.py +++ b/pyminion/__init__.py @@ -1,21 +1,10 @@ __version__ = "0.2.2" __author__ = "Evan Slack" - -# INITIALIZE LOGGER - import logging +# initalize logger with no handler. +# handlers are added in the `Game` init logger = logging.getLogger() -logger.setLevel(logging.DEBUG) - -# Create handler -c_handler = logging.StreamHandler() -c_handler.setLevel(logging.DEBUG) - -# Create formatter and add to handler -c_format = logging.Formatter("%(message)s") -c_handler.setFormatter(c_format) - -# Add handler to the logger -logger.addHandler(c_handler) +logger.setLevel((logging.INFO)) +logger.addHandler(logging.NullHandler()) diff --git a/pyminion/game.py b/pyminion/game.py index fb359fa..084d9e6 100644 --- a/pyminion/game.py +++ b/pyminion/game.py @@ -23,7 +23,8 @@ class Game: kingdom_cards: Specify any specific cards to be used in the supply. start_deck: List of cards each player will start the game with. Default = [7 Coppers + 3 Estates]. random_order: If True, scrambles the order of players (to offset first player advantage). - use_logger: If True, logs the game to a log file. + log_stdout: If True, logs game to stdout. + log_file: If True, logs game to log file. log_file_name: Name of the file to be logged to. Default = "game.log" """ @@ -35,7 +36,8 @@ def __init__( kingdom_cards: Optional[List[Card]] = None, start_deck: Optional[List[Card]] = None, random_order: bool = True, - use_logger: bool = True, + log_stdout: bool = True, + log_file: bool = False, log_file_name: str = "game.log", ): @@ -50,7 +52,15 @@ def __init__( self.random_order = random_order self.trash = Trash() - if use_logger: + if log_stdout: + # Set up a handler that logs to stdout + c_handler = logging.StreamHandler() + c_handler.setLevel(logging.INFO) + c_format = logging.Formatter("%(message)s") + c_handler.setFormatter(c_format) + logger.addHandler(c_handler) + + if log_file: # Set up a handler that dumps the log to a file f_handler = logging.FileHandler(log_file_name, mode="w") f_handler.setLevel(logging.INFO) From a228465a1459894baeb389f9fdafec59c090e215 Mon Sep 17 00:00:00 2001 From: evanofslack Date: Sun, 5 Feb 2023 00:26:37 -0500 Subject: [PATCH 6/7] update examples --- examples/bot_game.py | 13 ++++++++++--- examples/human_game.py | 10 +++++----- examples/simulation.py | 4 +++- 3 files changed, 18 insertions(+), 9 deletions(-) diff --git a/examples/bot_game.py b/examples/bot_game.py index 2e2fc4c..60fe26c 100644 --- a/examples/bot_game.py +++ b/examples/bot_game.py @@ -1,6 +1,10 @@ """ Run a single game between two bots. +Here we do not log the game to console. +Instead, we save the game output to a file (pyminion.log). +We only print the result of the game to console. + """ from pyminion.bots.examples import BigMoney, BigMoneyUltimate @@ -14,10 +18,13 @@ game = Game( players=[bm, bm_ultimate], expansions=[base_set], - kingdom_cards=[smithy], - use_logger=True, - log_file_name="pyminion.log", + kingdom_cards=[smithy], # specific cards to add to the kingdom + random_order=True, # players start in random order + log_stdout=False, # log the output to stdout + log_file=True, # log the output to file + log_file_name="pyminion.log", # name of file to log output ) if __name__ == "__main__": result = game.play() + print(result) diff --git a/examples/human_game.py b/examples/human_game.py index 9e1f7c3..2d18ef2 100644 --- a/examples/human_game.py +++ b/examples/human_game.py @@ -1,5 +1,6 @@ """ -Play a game through the terminal. Either by yourself, with another human, or against a bot. +Play a game through the terminal. +Either by yourself, with another human, or against a bot. """ @@ -9,14 +10,13 @@ from pyminion.players import Human human = Human(player_id="Human") -bm = BigMoney(player_id="Big Moneu") +bm = BigMoney(player_id="Big Money") game = Game( players=[human, bm], expansions=[base_set], - kingdom_cards=[artisan, bandit, witch], - use_logger=True, - log_file_name="pyminion.log", + kingdom_cards=[artisan, bandit, witch], # specific cards to add to the kingdom + random_order=True, # players start in random order ) if __name__ == "__main__": diff --git a/examples/simulation.py b/examples/simulation.py index 949c442..f7195d6 100644 --- a/examples/simulation.py +++ b/examples/simulation.py @@ -15,7 +15,9 @@ players=[bm, bm_smithy], expansions=[base_set], kingdom_cards=[smithy], - use_logger=False, + random_order=False, + log_stdout=False, + log_file=False, ) sim = Simulator(game, iterations=1000) From e4b9631dface6fdfee1d9adb428bb580d92be211 Mon Sep 17 00:00:00 2001 From: evanofslack Date: Sun, 5 Feb 2023 00:37:06 -0500 Subject: [PATCH 7/7] add turn order to player summary fix test --- pyminion/game.py | 3 ++- pyminion/result.py | 18 +++++++++++++++++- tests/test_players/test_bots/test_bot_game.py | 3 --- 3 files changed, 19 insertions(+), 5 deletions(-) diff --git a/pyminion/game.py b/pyminion/game.py index 084d9e6..a78efe1 100644 --- a/pyminion/game.py +++ b/pyminion/game.py @@ -281,7 +281,7 @@ def summerize_game(self) -> GameResult: player_summaries = [] winners = self.get_winners() - for player in self.players: + for order, player in enumerate(self.players): # player won if player in winners and len(winners) == 1: @@ -301,6 +301,7 @@ def summerize_game(self) -> GameResult: score=player.get_victory_points(), turns=player.turns, shuffles=player.shuffles, + turn_order=order + 1, deck=DeckCounter(player.get_all_cards()), ) player_summaries.append(summary) diff --git a/pyminion/result.py b/pyminion/result.py index b3dcb31..8f74f06 100644 --- a/pyminion/result.py +++ b/pyminion/result.py @@ -31,17 +31,33 @@ class PlayerSummary: score: int turns: int shuffles: int + turn_order: int deck: "DeckCounter" def __repr__(self): + + order_format = "None" + if self.turn_order == 1: + order_format = "1st" + + elif self.turn_order == 2: + order_format = "2nd" + + elif self.turn_order == 3: + order_format = "3rd" + + elif self.turn_order == 4: + order_format = "4th" + player = f"Player: {self.player.player_id}" result = f"Result: {self.result.name}" score = f"Score: {self.score}" turns = f"Turns: {self.turns}" shuffles = f"Shuffles: {self.shuffles}" + order = f"Turn Order: {order_format}" deck = f"Deck: {self.deck}" - return f"{player}\n{result}\n{score}\n{turns}\n{shuffles}\n{deck}" + return f"{player}\n{result}\n{score}\n{turns}\n{shuffles}\n{order}\n{deck}" @dataclass diff --git a/tests/test_players/test_bots/test_bot_game.py b/tests/test_players/test_bots/test_bot_game.py index 86aad7b..c2a2958 100644 --- a/tests/test_players/test_bots/test_bot_game.py +++ b/tests/test_players/test_bots/test_bot_game.py @@ -9,7 +9,6 @@ def test_game_single_player_play(bm_bot: BigMoney): players=[bm_bot], expansions=[base_set], kingdom_cards=[smithy], - use_logger=False, ) game.play() assert game.get_winners() == [bm_bot] @@ -20,7 +19,6 @@ def test_game_2_player_play(bm_bot: BigMoney): players=[bm_bot, bm_bot], expansions=[base_set], kingdom_cards=[smithy], - use_logger=False, ) game.play() assert len(game.get_winners()) >= 1 @@ -32,7 +30,6 @@ def test_game_2_player_with_actions(): players=[bot, bot], expansions=[base_set], kingdom_cards=[smithy], - use_logger=False, ) game.play() assert len(game.get_winners()) >= 1