i151-engine 0.2.3__tar.gz → 0.2.4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {i151_engine-0.2.3 → i151_engine-0.2.4}/ARCHITECTURE.md +2 -2
- {i151_engine-0.2.3 → i151_engine-0.2.4}/PKG-INFO +1 -1
- {i151_engine-0.2.3 → i151_engine-0.2.4}/i151_engine/core/scoring.py +4 -1
- {i151_engine-0.2.3 → i151_engine-0.2.4}/i151_engine/game/recorder.py +1 -1
- {i151_engine-0.2.3 → i151_engine-0.2.4}/i151_engine/runner/config.py +1 -1
- {i151_engine-0.2.3 → i151_engine-0.2.4}/i151_engine.egg-info/PKG-INFO +1 -1
- {i151_engine-0.2.3 → i151_engine-0.2.4}/pyproject.toml +1 -1
- {i151_engine-0.2.3 → i151_engine-0.2.4}/tests/test_scoring.py +53 -0
- {i151_engine-0.2.3 → i151_engine-0.2.4}/README.md +0 -0
- {i151_engine-0.2.3 → i151_engine-0.2.4}/i151_engine/__init__.py +0 -0
- {i151_engine-0.2.3 → i151_engine-0.2.4}/i151_engine/bots/__init__.py +0 -0
- {i151_engine-0.2.3 → i151_engine-0.2.4}/i151_engine/bots/protocol.py +0 -0
- {i151_engine-0.2.3 → i151_engine-0.2.4}/i151_engine/bots/random_bot.py +0 -0
- {i151_engine-0.2.3 → i151_engine-0.2.4}/i151_engine/core/__init__.py +0 -0
- {i151_engine-0.2.3 → i151_engine-0.2.4}/i151_engine/core/deck.py +0 -0
- {i151_engine-0.2.3 → i151_engine-0.2.4}/i151_engine/core/errors.py +0 -0
- {i151_engine-0.2.3 → i151_engine-0.2.4}/i151_engine/core/legal_actions.py +0 -0
- {i151_engine-0.2.3 → i151_engine-0.2.4}/i151_engine/core/reducer.py +0 -0
- {i151_engine-0.2.3 → i151_engine-0.2.4}/i151_engine/core/rules.py +0 -0
- {i151_engine-0.2.3 → i151_engine-0.2.4}/i151_engine/game/__init__.py +0 -0
- {i151_engine-0.2.3 → i151_engine-0.2.4}/i151_engine/game/round.py +0 -0
- {i151_engine-0.2.3 → i151_engine-0.2.4}/i151_engine/game/round_state.py +0 -0
- {i151_engine-0.2.3 → i151_engine-0.2.4}/i151_engine/models/__init__.py +0 -0
- {i151_engine-0.2.3 → i151_engine-0.2.4}/i151_engine/models/action.py +0 -0
- {i151_engine-0.2.3 → i151_engine-0.2.4}/i151_engine/models/card.py +0 -0
- {i151_engine-0.2.3 → i151_engine-0.2.4}/i151_engine/models/enums.py +0 -0
- {i151_engine-0.2.3 → i151_engine-0.2.4}/i151_engine/models/player.py +0 -0
- {i151_engine-0.2.3 → i151_engine-0.2.4}/i151_engine/opponents/__init__.py +0 -0
- {i151_engine-0.2.3 → i151_engine-0.2.4}/i151_engine/opponents/catalog.py +0 -0
- {i151_engine-0.2.3 → i151_engine-0.2.4}/i151_engine/opponents/registry.py +0 -0
- {i151_engine-0.2.3 → i151_engine-0.2.4}/i151_engine/opponents/schedules.py +0 -0
- {i151_engine-0.2.3 → i151_engine-0.2.4}/i151_engine/opponents/types.py +0 -0
- {i151_engine-0.2.3 → i151_engine-0.2.4}/i151_engine/runner/challenge_guards.py +0 -0
- {i151_engine-0.2.3 → i151_engine-0.2.4}/i151_engine/runner/match_runner.py +0 -0
- {i151_engine-0.2.3 → i151_engine-0.2.4}/i151_engine/view/builder.py +0 -0
- {i151_engine-0.2.3 → i151_engine-0.2.4}/i151_engine/view/player_view.py +0 -0
- {i151_engine-0.2.3 → i151_engine-0.2.4}/i151_engine.egg-info/SOURCES.txt +0 -0
- {i151_engine-0.2.3 → i151_engine-0.2.4}/i151_engine.egg-info/dependency_links.txt +0 -0
- {i151_engine-0.2.3 → i151_engine-0.2.4}/i151_engine.egg-info/requires.txt +0 -0
- {i151_engine-0.2.3 → i151_engine-0.2.4}/i151_engine.egg-info/top_level.txt +0 -0
- {i151_engine-0.2.3 → i151_engine-0.2.4}/setup.cfg +0 -0
- {i151_engine-0.2.3 → i151_engine-0.2.4}/tests/test_card.py +0 -0
- {i151_engine-0.2.3 → i151_engine-0.2.4}/tests/test_challenge_guards.py +0 -0
- {i151_engine-0.2.3 → i151_engine-0.2.4}/tests/test_deck.py +0 -0
- {i151_engine-0.2.3 → i151_engine-0.2.4}/tests/test_first_player.py +0 -0
- {i151_engine-0.2.3 → i151_engine-0.2.4}/tests/test_forfeit_scoring.py +0 -0
- {i151_engine-0.2.3 → i151_engine-0.2.4}/tests/test_match_runner.py +0 -0
- {i151_engine-0.2.3 → i151_engine-0.2.4}/tests/test_match_timeout.py +0 -0
- {i151_engine-0.2.3 → i151_engine-0.2.4}/tests/test_opponents.py +0 -0
- {i151_engine-0.2.3 → i151_engine-0.2.4}/tests/test_player_view_turn.py +0 -0
- {i151_engine-0.2.3 → i151_engine-0.2.4}/tests/test_recorder.py +0 -0
- {i151_engine-0.2.3 → i151_engine-0.2.4}/tests/test_reducer.py +0 -0
- {i151_engine-0.2.3 → i151_engine-0.2.4}/tests/test_rules.py +0 -0
|
@@ -606,7 +606,7 @@ def decide(view: PlayerView, legal_actions: list[Action], time_left_ms: int) ->
|
|
|
606
606
|
| Taille ZIP | 50 Mo |
|
|
607
607
|
| Fichier modèle unique | 30 Mo |
|
|
608
608
|
| Temps `setup()` | 30 s |
|
|
609
|
-
| Temps `decide()` | `decision_timeout_ms` (
|
|
609
|
+
| Temps `decide()` | `decision_timeout_ms` (1000 ms par défaut) |
|
|
610
610
|
| RAM processus | 512 Mo |
|
|
611
611
|
|
|
612
612
|
Le runner charge le bot une fois par match (`setup` → boucle `decide` → `teardown`).
|
|
@@ -787,7 +787,7 @@ Les parties générées localement n'alimentent pas le classement ; seules les s
|
|
|
787
787
|
class MatchConfig:
|
|
788
788
|
seed: int
|
|
789
789
|
target_score: int = 151
|
|
790
|
-
decision_timeout_ms: int =
|
|
790
|
+
decision_timeout_ms: int = 1000
|
|
791
791
|
match_timeout_ms: int = 600_000
|
|
792
792
|
max_steps_per_round: int = 500 # garde-fou anti-boucle
|
|
793
793
|
|
|
@@ -108,7 +108,8 @@ def apply_round_scoring(match: MatchState, winner_id: str) -> MatchState:
|
|
|
108
108
|
is_excluded=player.is_excluded or new_score >= match.target_score,
|
|
109
109
|
has_drawn_this_turn=False,
|
|
110
110
|
is_chaining=False,
|
|
111
|
-
|
|
111
|
+
# Aligné Flutter/TS : série cassée dès qu'un autre gagne la manche.
|
|
112
|
+
consecutive_round_wins=0,
|
|
112
113
|
)
|
|
113
114
|
|
|
114
115
|
winner, last_winner_id = _track_consecutive_wins(
|
|
@@ -130,6 +131,7 @@ def apply_round_scoring(match: MatchState, winner_id: str) -> MatchState:
|
|
|
130
131
|
winner_id=winner_id_final,
|
|
131
132
|
current_round=None,
|
|
132
133
|
seed=match.seed,
|
|
134
|
+
cards_per_player=match.cards_per_player,
|
|
133
135
|
)
|
|
134
136
|
|
|
135
137
|
dealer_index, _ = _next_dealer_and_starter(players_list, match.dealer_index)
|
|
@@ -143,6 +145,7 @@ def apply_round_scoring(match: MatchState, winner_id: str) -> MatchState:
|
|
|
143
145
|
winner_id=None,
|
|
144
146
|
current_round=None,
|
|
145
147
|
seed=match.seed,
|
|
148
|
+
cards_per_player=match.cards_per_player,
|
|
146
149
|
)
|
|
147
150
|
|
|
148
151
|
|
|
@@ -81,3 +81,56 @@ def test_consecutive_win_bonus_deducts_ten_from_winner():
|
|
|
81
81
|
result = apply_round_scoring(match, "p0")
|
|
82
82
|
assert result.player_by_id("p0").total_score == 40
|
|
83
83
|
assert result.player_by_id("p0").consecutive_round_wins == 0
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def test_losing_resets_consecutive_round_wins():
|
|
87
|
+
"""Régression : sans reset, la vue exposait une série fantôme au perdant."""
|
|
88
|
+
end_p0 = PlayerState(player_id="p0", name="NewWinner", hand=())
|
|
89
|
+
end_p1 = PlayerState(player_id="p1", name="PrevStreak", hand=(Card(Rank.SEVEN, Suit.CLUBS),))
|
|
90
|
+
|
|
91
|
+
round_state = _ended_round(players=(end_p0, end_p1), winner_id="p0")
|
|
92
|
+
match = MatchState(
|
|
93
|
+
status=MatchStatus.IN_PROGRESS,
|
|
94
|
+
players=(
|
|
95
|
+
PlayerState("p0", "NewWinner", hand=(), total_score=10, consecutive_round_wins=0),
|
|
96
|
+
PlayerState("p1", "PrevStreak", hand=(), total_score=20, consecutive_round_wins=2),
|
|
97
|
+
),
|
|
98
|
+
round_number=3,
|
|
99
|
+
dealer_index=0,
|
|
100
|
+
target_score=151,
|
|
101
|
+
last_winner_id="p1",
|
|
102
|
+
winner_id=None,
|
|
103
|
+
current_round=round_state,
|
|
104
|
+
seed=1,
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
result = apply_round_scoring(match, "p0")
|
|
108
|
+
assert result.player_by_id("p0").consecutive_round_wins == 1
|
|
109
|
+
assert result.player_by_id("p1").consecutive_round_wins == 0
|
|
110
|
+
assert result.last_winner_id == "p0"
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
def test_apply_round_scoring_preserves_cards_per_player():
|
|
114
|
+
"""Régression : sans ce champ, la manche 2 repasse à 8 cartes (banque=16)."""
|
|
115
|
+
end_p0 = PlayerState(player_id="p0", name="A", hand=())
|
|
116
|
+
end_p1 = PlayerState(player_id="p1", name="B", hand=(Card(Rank.SEVEN, Suit.CLUBS),))
|
|
117
|
+
round_state = _ended_round(players=(end_p0, end_p1), winner_id="p0")
|
|
118
|
+
match = MatchState(
|
|
119
|
+
status=MatchStatus.IN_PROGRESS,
|
|
120
|
+
players=(
|
|
121
|
+
PlayerState("p0", "A", hand=()),
|
|
122
|
+
PlayerState("p1", "B", hand=()),
|
|
123
|
+
),
|
|
124
|
+
round_number=1,
|
|
125
|
+
dealer_index=0,
|
|
126
|
+
target_score=151,
|
|
127
|
+
last_winner_id=None,
|
|
128
|
+
winner_id=None,
|
|
129
|
+
current_round=round_state,
|
|
130
|
+
seed=1,
|
|
131
|
+
cards_per_player=16,
|
|
132
|
+
)
|
|
133
|
+
result = apply_round_scoring(match, "p0")
|
|
134
|
+
assert result.status == MatchStatus.IN_PROGRESS
|
|
135
|
+
assert result.cards_per_player == 16
|
|
136
|
+
assert result.round_number == 2
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|