mirror of
https://github.com/RichieCahill/dotfiles.git
synced 2026-04-17 04:58:19 -04:00
get splendor code ruff complient
This commit is contained in:
@@ -51,6 +51,7 @@ lint.ignore = [
|
|||||||
"python/splendor/**" = [
|
"python/splendor/**" = [
|
||||||
"S311", # (perm) there is no security issue here
|
"S311", # (perm) there is no security issue here
|
||||||
"T201", # (perm) I don't care about print statements dir
|
"T201", # (perm) I don't care about print statements dir
|
||||||
|
"PLR2004", # (temps) need to think about this
|
||||||
]
|
]
|
||||||
|
|
||||||
[tool.ruff.lint.pydocstyle]
|
[tool.ruff.lint.pydocstyle]
|
||||||
|
|||||||
@@ -471,7 +471,8 @@ def apply_action(game: GameState, strategy: Strategy, action: Action) -> None:
|
|||||||
action_func(game, strategy, action)
|
action_func(game, strategy, action)
|
||||||
|
|
||||||
|
|
||||||
def get_legal_actions(
|
# not sure how to simplify this yet
|
||||||
|
def get_legal_actions( # noqa: C901
|
||||||
game: GameState,
|
game: GameState,
|
||||||
player: PlayerState | None = None,
|
player: PlayerState | None = None,
|
||||||
) -> list[Action]:
|
) -> list[Action]:
|
||||||
|
|||||||
@@ -38,9 +38,11 @@ class RandomBot(Strategy):
|
|||||||
"""Dumb bot that follows rules but doesn't think."""
|
"""Dumb bot that follows rules but doesn't think."""
|
||||||
|
|
||||||
def __init__(self, name: str) -> None:
|
def __init__(self, name: str) -> None:
|
||||||
|
"""Initialize the bot."""
|
||||||
super().__init__(name=name)
|
super().__init__(name=name)
|
||||||
|
|
||||||
def choose_action(self, game: GameState, player: PlayerState) -> Action | None:
|
def choose_action(self, game: GameState, player: PlayerState) -> Action | None:
|
||||||
|
"""Choose an action for the current player."""
|
||||||
affordable: list[tuple[int, int]] = []
|
affordable: list[tuple[int, int]] = []
|
||||||
for tier, row in game.table_by_tier.items():
|
for tier, row in game.table_by_tier.items():
|
||||||
for idx, card in enumerate(row):
|
for idx, card in enumerate(row):
|
||||||
@@ -68,17 +70,21 @@ class RandomBot(Strategy):
|
|||||||
|
|
||||||
def choose_discard(
|
def choose_discard(
|
||||||
self,
|
self,
|
||||||
game: GameState,
|
game: GameState, # noqa: ARG002
|
||||||
player: PlayerState,
|
player: PlayerState,
|
||||||
excess: int,
|
excess: int,
|
||||||
) -> dict[GemColor, int]:
|
) -> dict[GemColor, int]:
|
||||||
|
"""Choose how many tokens to discard."""
|
||||||
return auto_discard_tokens(player, excess)
|
return auto_discard_tokens(player, excess)
|
||||||
|
|
||||||
|
|
||||||
class PersonalizedBot(Strategy):
|
class PersonalizedBot(Strategy):
|
||||||
|
"""PersonalizedBot."""
|
||||||
|
|
||||||
"""Dumb bot that follows rules but doesn't think."""
|
"""Dumb bot that follows rules but doesn't think."""
|
||||||
|
|
||||||
def __init__(self, name: str) -> None:
|
def __init__(self, name: str) -> None:
|
||||||
|
"""Initialize the bot."""
|
||||||
super().__init__(name=name)
|
super().__init__(name=name)
|
||||||
|
|
||||||
def check_cards_in_tier(self, row: list[Card], player: PlayerState) -> bool:
|
def check_cards_in_tier(self, row: list[Card], player: PlayerState) -> bool:
|
||||||
@@ -86,6 +92,7 @@ class PersonalizedBot(Strategy):
|
|||||||
return [index for index, card in enumerate(row) if can_bot_afford(player, card)]
|
return [index for index, card in enumerate(row) if can_bot_afford(player, card)]
|
||||||
|
|
||||||
def choose_action(self, game: GameState, player: PlayerState) -> Action | None:
|
def choose_action(self, game: GameState, player: PlayerState) -> Action | None:
|
||||||
|
"""Choose an action for the current player."""
|
||||||
for tier in (1, 2, 3):
|
for tier in (1, 2, 3):
|
||||||
row = game.table_by_tier[tier]
|
row = game.table_by_tier[tier]
|
||||||
if affordable := check_cards_in_tier(row, player):
|
if affordable := check_cards_in_tier(row, player):
|
||||||
@@ -98,10 +105,11 @@ class PersonalizedBot(Strategy):
|
|||||||
|
|
||||||
def choose_discard(
|
def choose_discard(
|
||||||
self,
|
self,
|
||||||
game: GameState,
|
game: GameState, # noqa: ARG002
|
||||||
player: PlayerState,
|
player: PlayerState,
|
||||||
excess: int,
|
excess: int,
|
||||||
) -> dict[GemColor, int]:
|
) -> dict[GemColor, int]:
|
||||||
|
"""Choose how many tokens to discard."""
|
||||||
return auto_discard_tokens(player, excess)
|
return auto_discard_tokens(player, excess)
|
||||||
|
|
||||||
|
|
||||||
@@ -111,12 +119,16 @@ def check_cards_in_tier(row: list[Card], player: PlayerState) -> bool:
|
|||||||
|
|
||||||
|
|
||||||
class PersonalizedBot2(Strategy):
|
class PersonalizedBot2(Strategy):
|
||||||
|
"""PersonalizedBot2."""
|
||||||
|
|
||||||
"""Dumb bot that follows rules but doesn't think."""
|
"""Dumb bot that follows rules but doesn't think."""
|
||||||
|
|
||||||
def __init__(self, name: str) -> None:
|
def __init__(self, name: str) -> None:
|
||||||
|
"""Initialize the bot."""
|
||||||
super().__init__(name=name)
|
super().__init__(name=name)
|
||||||
|
|
||||||
def choose_action(self, game: GameState, player: PlayerState) -> Action | None:
|
def choose_action(self, game: GameState, player: PlayerState) -> Action | None:
|
||||||
|
"""Choose an action for the current player."""
|
||||||
tiers = (1, 2, 3)
|
tiers = (1, 2, 3)
|
||||||
for tier in tiers:
|
for tier in tiers:
|
||||||
row = game.table_by_tier[tier]
|
row = game.table_by_tier[tier]
|
||||||
@@ -142,14 +154,16 @@ class PersonalizedBot2(Strategy):
|
|||||||
|
|
||||||
def choose_discard(
|
def choose_discard(
|
||||||
self,
|
self,
|
||||||
game: GameState,
|
game: GameState, # noqa: ARG002
|
||||||
player: PlayerState,
|
player: PlayerState,
|
||||||
excess: int,
|
excess: int,
|
||||||
) -> dict[GemColor, int]:
|
) -> dict[GemColor, int]:
|
||||||
|
"""Choose how many tokens to discard."""
|
||||||
return auto_discard_tokens(player, excess)
|
return auto_discard_tokens(player, excess)
|
||||||
|
|
||||||
|
|
||||||
def buy_card_reserved(player: PlayerState) -> Action | None:
|
def buy_card_reserved(player: PlayerState) -> Action | None:
|
||||||
|
"""Buy a card reserved."""
|
||||||
if affordable := check_cards_in_tier(player.reserved, player):
|
if affordable := check_cards_in_tier(player.reserved, player):
|
||||||
index = random.choice(affordable)
|
index = random.choice(affordable)
|
||||||
return BuyCardReserved(index=index)
|
return BuyCardReserved(index=index)
|
||||||
@@ -157,6 +171,7 @@ def buy_card_reserved(player: PlayerState) -> Action | None:
|
|||||||
|
|
||||||
|
|
||||||
def buy_card(game: GameState, player: PlayerState) -> Action | None:
|
def buy_card(game: GameState, player: PlayerState) -> Action | None:
|
||||||
|
"""Buy a card."""
|
||||||
for tier in (1, 2, 3):
|
for tier in (1, 2, 3):
|
||||||
row = game.table_by_tier[tier]
|
row = game.table_by_tier[tier]
|
||||||
if affordable := check_cards_in_tier(row, player):
|
if affordable := check_cards_in_tier(row, player):
|
||||||
@@ -166,6 +181,7 @@ def buy_card(game: GameState, player: PlayerState) -> Action | None:
|
|||||||
|
|
||||||
|
|
||||||
def take_toekns(game: GameState) -> Action | None:
|
def take_toekns(game: GameState) -> Action | None:
|
||||||
|
"""Take tokens."""
|
||||||
colors_for_diff = [color for color in BASE_COLORS if game.bank[color] > 0]
|
colors_for_diff = [color for color in BASE_COLORS if game.bank[color] > 0]
|
||||||
if len(colors_for_diff) >= 3:
|
if len(colors_for_diff) >= 3:
|
||||||
random.shuffle(colors_for_diff)
|
random.shuffle(colors_for_diff)
|
||||||
@@ -174,12 +190,16 @@ def take_toekns(game: GameState) -> Action | None:
|
|||||||
|
|
||||||
|
|
||||||
class PersonalizedBot3(Strategy):
|
class PersonalizedBot3(Strategy):
|
||||||
|
"""PersonalizedBot3."""
|
||||||
|
|
||||||
"""Dumb bot that follows rules but doesn't think."""
|
"""Dumb bot that follows rules but doesn't think."""
|
||||||
|
|
||||||
def __init__(self, name: str) -> None:
|
def __init__(self, name: str) -> None:
|
||||||
|
"""Initialize the bot."""
|
||||||
super().__init__(name=name)
|
super().__init__(name=name)
|
||||||
|
|
||||||
def choose_action(self, game: GameState, player: PlayerState) -> Action | None:
|
def choose_action(self, game: GameState, player: PlayerState) -> Action | None:
|
||||||
|
"""Choose an action for the current player."""
|
||||||
print(len(get_legal_actions(game, player)))
|
print(len(get_legal_actions(game, player)))
|
||||||
print(get_legal_actions(game, player))
|
print(get_legal_actions(game, player))
|
||||||
if action := buy_card_reserved(player):
|
if action := buy_card_reserved(player):
|
||||||
@@ -201,10 +221,11 @@ class PersonalizedBot3(Strategy):
|
|||||||
|
|
||||||
def choose_discard(
|
def choose_discard(
|
||||||
self,
|
self,
|
||||||
game: GameState,
|
game: GameState, # noqa: ARG002
|
||||||
player: PlayerState,
|
player: PlayerState,
|
||||||
excess: int,
|
excess: int,
|
||||||
) -> dict[GemColor, int]:
|
) -> dict[GemColor, int]:
|
||||||
|
"""Choose how many tokens to discard."""
|
||||||
return auto_discard_tokens(player, excess)
|
return auto_discard_tokens(player, excess)
|
||||||
|
|
||||||
|
|
||||||
@@ -219,10 +240,14 @@ def estimate_value_of_token(game: GameState, player: PlayerState, color: GemColo
|
|||||||
|
|
||||||
|
|
||||||
class PersonalizedBot4(Strategy):
|
class PersonalizedBot4(Strategy):
|
||||||
|
"""PersonalizedBot4."""
|
||||||
|
|
||||||
def __init__(self, name: str) -> None:
|
def __init__(self, name: str) -> None:
|
||||||
|
"""Initialize the bot."""
|
||||||
super().__init__(name=name)
|
super().__init__(name=name)
|
||||||
|
|
||||||
def filter_actions(self, actions: list[Action]) -> list[Action]:
|
def filter_actions(self, actions: list[Action]) -> list[Action]:
|
||||||
|
"""Filter actions to only take different."""
|
||||||
return [
|
return [
|
||||||
action
|
action
|
||||||
for action in actions
|
for action in actions
|
||||||
@@ -230,6 +255,7 @@ class PersonalizedBot4(Strategy):
|
|||||||
]
|
]
|
||||||
|
|
||||||
def choose_action(self, game: GameState, player: PlayerState) -> Action | None:
|
def choose_action(self, game: GameState, player: PlayerState) -> Action | None:
|
||||||
|
"""Choose an action for the current player."""
|
||||||
legal_actions = get_legal_actions(game, player)
|
legal_actions = get_legal_actions(game, player)
|
||||||
print(len(legal_actions))
|
print(len(legal_actions))
|
||||||
|
|
||||||
@@ -258,8 +284,9 @@ class PersonalizedBot4(Strategy):
|
|||||||
|
|
||||||
def choose_discard(
|
def choose_discard(
|
||||||
self,
|
self,
|
||||||
game: GameState,
|
game: GameState, # noqa: ARG002
|
||||||
player: PlayerState,
|
player: PlayerState,
|
||||||
excess: int,
|
excess: int,
|
||||||
) -> dict[GemColor, int]:
|
) -> dict[GemColor, int]:
|
||||||
|
"""Choose how many tokens to discard."""
|
||||||
return auto_discard_tokens(player, excess)
|
return auto_discard_tokens(player, excess)
|
||||||
|
|||||||
@@ -407,7 +407,7 @@ class ActionApp(App[None]):
|
|||||||
|
|
||||||
def _cmd_2(self, parts: list[str]) -> str | None:
|
def _cmd_2(self, parts: list[str]) -> str | None:
|
||||||
"""Take two of the same color."""
|
"""Take two of the same color."""
|
||||||
if len(parts) < 2: # noqa: PLR2004
|
if len(parts) < 2:
|
||||||
return "Usage: 2 <color>"
|
return "Usage: 2 <color>"
|
||||||
color = parse_color_token(parts[1])
|
color = parse_color_token(parts[1])
|
||||||
if self.game.bank[color] < self.game.config.minimum_tokens_to_buy_2:
|
if self.game.bank[color] < self.game.config.minimum_tokens_to_buy_2:
|
||||||
@@ -418,7 +418,7 @@ class ActionApp(App[None]):
|
|||||||
|
|
||||||
def _cmd_3(self, parts: list[str]) -> str | None:
|
def _cmd_3(self, parts: list[str]) -> str | None:
|
||||||
"""Buy face-up card."""
|
"""Buy face-up card."""
|
||||||
if len(parts) < 3: # noqa: PLR2004
|
if len(parts) < 3:
|
||||||
return "Usage: 3 <tier> <index>"
|
return "Usage: 3 <tier> <index>"
|
||||||
tier = int(parts[1])
|
tier = int(parts[1])
|
||||||
idx = int(parts[2])
|
idx = int(parts[2])
|
||||||
@@ -428,7 +428,7 @@ class ActionApp(App[None]):
|
|||||||
|
|
||||||
def _cmd_4(self, parts: list[str]) -> str | None:
|
def _cmd_4(self, parts: list[str]) -> str | None:
|
||||||
"""Buy reserved card."""
|
"""Buy reserved card."""
|
||||||
if len(parts) < 2: # noqa: PLR2004
|
if len(parts) < 2:
|
||||||
return "Usage: 4 <reserved_index>"
|
return "Usage: 4 <reserved_index>"
|
||||||
idx = int(parts[1])
|
idx = int(parts[1])
|
||||||
if not (0 <= idx < len(self.player.reserved)):
|
if not (0 <= idx < len(self.player.reserved)):
|
||||||
@@ -439,7 +439,7 @@ class ActionApp(App[None]):
|
|||||||
|
|
||||||
def _cmd_5(self, parts: list[str]) -> str | None:
|
def _cmd_5(self, parts: list[str]) -> str | None:
|
||||||
"""Reserve face-up card."""
|
"""Reserve face-up card."""
|
||||||
if len(parts) < 3: # noqa: PLR2004
|
if len(parts) < 3:
|
||||||
return "Usage: 5 <tier> <index>"
|
return "Usage: 5 <tier> <index>"
|
||||||
tier = int(parts[1])
|
tier = int(parts[1])
|
||||||
idx = int(parts[2])
|
idx = int(parts[2])
|
||||||
@@ -449,7 +449,7 @@ class ActionApp(App[None]):
|
|||||||
|
|
||||||
def _cmd_6(self, parts: list[str]) -> str | None:
|
def _cmd_6(self, parts: list[str]) -> str | None:
|
||||||
"""Reserve top of deck."""
|
"""Reserve top of deck."""
|
||||||
if len(parts) < 2: # noqa: PLR2004
|
if len(parts) < 2:
|
||||||
return "Usage: 6 <tier>"
|
return "Usage: 6 <tier>"
|
||||||
tier = int(parts[1])
|
tier = int(parts[1])
|
||||||
self.result = ReserveCard(tier=tier, index=None, from_deck=True)
|
self.result = ReserveCard(tier=tier, index=None, from_deck=True)
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
"""Main entry point for Splendor game."""
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from .base import new_game, run_game
|
from .base import new_game, run_game
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
"""Public state for RL/search."""
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
@@ -25,12 +27,16 @@ class ObsCard:
|
|||||||
|
|
||||||
@dataclass(frozen=True)
|
@dataclass(frozen=True)
|
||||||
class ObsNoble:
|
class ObsNoble:
|
||||||
|
"""Numeric-ish noble view for RL/search."""
|
||||||
|
|
||||||
points: int
|
points: int
|
||||||
requirements: list[int]
|
requirements: list[int]
|
||||||
|
|
||||||
|
|
||||||
@dataclass(frozen=True)
|
@dataclass(frozen=True)
|
||||||
class ObsPlayer:
|
class ObsPlayer:
|
||||||
|
"""Numeric-ish player view for RL/search."""
|
||||||
|
|
||||||
tokens: list[int]
|
tokens: list[int]
|
||||||
discounts: list[int]
|
discounts: list[int]
|
||||||
score: int
|
score: int
|
||||||
@@ -41,6 +47,8 @@ class ObsPlayer:
|
|||||||
|
|
||||||
@dataclass(frozen=True)
|
@dataclass(frozen=True)
|
||||||
class Observation:
|
class Observation:
|
||||||
|
"""Full public state for RL/search."""
|
||||||
|
|
||||||
current_player: int
|
current_player: int
|
||||||
bank: list[int]
|
bank: list[int]
|
||||||
players: list[ObsPlayer]
|
players: list[ObsPlayer]
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
"""Simulate a step in the game."""
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import copy
|
import copy
|
||||||
@@ -13,7 +15,8 @@ class SimStrategy(RandomBot):
|
|||||||
but we reuse discard/noble-selection logic.
|
but we reuse discard/noble-selection logic.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def choose_action(self, game: GameState, player: PlayerState) -> Action | None:
|
def choose_action(self, game: GameState, player: PlayerState) -> Action | None: # noqa: ARG002
|
||||||
|
"""Choose an action for the current player."""
|
||||||
msg = "SimStrategy.choose_action should not be used in simulate_step"
|
msg = "SimStrategy.choose_action should not be used in simulate_step"
|
||||||
raise RuntimeError(msg)
|
raise RuntimeError(msg)
|
||||||
|
|
||||||
|
|||||||
@@ -39,7 +39,8 @@ def main() -> None:
|
|||||||
winners[winner.strategy.name].append(turns)
|
winners[winner.strategy.name].append(turns)
|
||||||
|
|
||||||
print(
|
print(
|
||||||
f"out of {games} {turn_limit} turn games with {len(players)} random bots there where {good_games} games where a bot won"
|
f"out of {games} {turn_limit} turn games with {len(players)}"
|
||||||
|
f"random bots there where {good_games} games where a bot won"
|
||||||
)
|
)
|
||||||
for name, turns in winners.items():
|
for name, turns in winners.items():
|
||||||
print(f"{name} won {len(turns)} games in {mean(turns):.2f} turns")
|
print(f"{name} won {len(turns)} games in {mean(turns):.2f} turns")
|
||||||
|
|||||||
Reference in New Issue
Block a user