V1 — Random, excluding End Turn
One bit of knowledge separates V1 from V0: doing things is better than passing. V1 is still uniform-random, but it never ends its turn voluntarily while any other move exists — it plays its cards, buys, and attacks (in no particular order) before passing. That single constraint is enough to beat V0 convincingly, because V0 regularly ends its turn with unplayed cards in hand and unspent combat on the table.
lesson_7/policies/v1/__init__.py
"""V1 -- choose randomly, excluding End Turn (unless it is the only option)."""
from __future__ import annotations
from random import Random
import star_engine as se
from ..base import Actions, Policy
from ..common import uniform_excluding_end_turn
class V1(Policy):
def __init__(self) -> None:
super().__init__("V1 Choose randomly, excluding end turn")
def get_action_probabilities(
self, game: se.Game, actions: Actions, rng: Random
) -> list[float]:
return uniform_excluding_end_turn(actions)
The helper handles the edge case: when End Turn is the only legal action, it is taken (with probability 1).
lesson_7/policies/common.py (excerpt)
def uniform_excluding_end_turn(actions: Actions) -> list[float]:
"""Uniform over all actions except End Turn; falls back to uniform over all
(i.e. just End Turn) when End Turn is the only legal action."""
non_end = [a for a in actions if a.category != se.CAT_END_TURN]
pool = non_end if non_end else list(actions)
keep = {a.index for a in pool}
p = 1.0 / len(pool)
return [p if a.index in keep else 0.0 for a in actions]