Bot-Man-Toe/agents/chaos.py

79 lines
2.5 KiB
Python

"""
The agent of chaos is an agent that always attempts to return a random
response.
In most games, the Agent of chaos makes two considerations:
1. Which moves are valid? Since invalid moves fallback to "default" moves,
this can destabilize the probability distribution, making some moves
more likely to be chosen than others. As a result, we refrain from
"invalid" moves and take the effort to filter them out.
2. What's a reasonable probability distribution? Sometimes, a uniform
distribution across all options doesn't make a lot of sense. For
example, imagine asking the agent every turn whether they want to
use their super duper special single-use ability, and leaving that to
a 50/50 call every turn. It feels much more random if such an ability
is more randomly used throughout the GAME, than to have every choice
be a uniformly distributed decision.
"""
from __future__ import annotations
import random
from .agent import Agent, Payload
class AgentOfChaos(Agent):
"""
The agent of chaos always aims to deliver a random response.
"""
def __init__(self) -> None:
"""
Agent that always tries to make a "random" move.
"""
super().__init__(
name="Agent of chaos",
author="Bram",
version="1.0.1",
profile={
"me.noordstar.peanuts.is_ai": False,
},
)
self.add_tic_tac_toe(on_move=play_tic_tac_toe, profile={})
self.add_royal_game_of_ur(on_move=play_royal_game_of_ur, profile={})
def play_tic_tac_toe(payload : Payload) -> Payload:
"""
In tic-tac-toe, the agent of chaos makes uniformly distributed choices
on unclaimed tiles.
:param payload: The incoming game state.
:type payload: dict[str, Any]
:return: The agent of chaos' random choice
:rtype: dict[str, Any]
"""
options = [
int(k)
for k, v in dict(payload).items()
if k in "0123456789" and v == ""
]
return { "move": random.choice(options) }
def play_royal_game_of_ur(payload : Payload) -> Payload:
"""
The royal game of Ur already returns a set of valid moves.
We can lazily just pick one of these options and return it.
:param payload: The incoming game state.
:type payload: dict[str, Any]
:return: The agent of chaos' random choice
:rtype: dict[str, Any]
"""
return { "move": random.choice(payload.get("valid_moves", [""])) }