Compare commits
2 Commits
main
...
bram/agent
| Author | SHA1 | Date |
|---|---|---|
|
|
884069621c | |
|
|
2abf07564c |
93
server.py
93
server.py
|
|
@ -1,5 +1,21 @@
|
||||||
"""
|
"""
|
||||||
This module enables a user to host a server that is able to play games.
|
This implementation describes the Agent of chaos. This agent mostly uses
|
||||||
|
randomness to determine which action to take.
|
||||||
|
|
||||||
|
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
|
from __future__ import annotations
|
||||||
|
|
@ -17,22 +33,19 @@ def main() -> int:
|
||||||
:rtype: int
|
:rtype: int
|
||||||
"""
|
"""
|
||||||
player = PyServer(
|
player = PyServer(
|
||||||
# Customize this to whatever you'd like to call your player
|
name="Agent of chaos",
|
||||||
name="My super smart robot player",
|
profile={
|
||||||
|
"me.noordstar.peanuts.author": "Bram",
|
||||||
# Custom information that you can use to tell people about this player
|
"me.noordstar.peanuts.containerized": True,
|
||||||
profile={},
|
"me.noordstar.peanuts.agent.version" : "1.0.0",
|
||||||
|
},
|
||||||
# Unless you know what you're doing, don't touch this.
|
|
||||||
import_name=__name__,
|
import_name=__name__,
|
||||||
)
|
)
|
||||||
|
|
||||||
# Register games! Comment out any you don't want your player to play.
|
|
||||||
player.add_tic_tac_toe(on_move=play_tic_tac_toe, profile={})
|
player.add_tic_tac_toe(on_move=play_tic_tac_toe, profile={})
|
||||||
|
|
||||||
# Start listening for games
|
|
||||||
player.start(
|
player.start(
|
||||||
host="0.0.0.0", # Comment out when using only locally
|
host="0.0.0.0",
|
||||||
port=5000,
|
port=5000,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -40,59 +53,19 @@ def main() -> int:
|
||||||
|
|
||||||
def play_tic_tac_toe(payload : dict[str, Any]) -> dict[str, Any]:
|
def play_tic_tac_toe(payload : dict[str, Any]) -> dict[str, Any]:
|
||||||
"""
|
"""
|
||||||
Play a game of tic-tac-toe.
|
In tic-tac-toe, the agent of chaos makes uniformly distributed choices
|
||||||
|
on unclaimed tiles.
|
||||||
|
|
||||||
You receive a payload that looks like this:
|
:param payload: The incoming game state.
|
||||||
|
|
||||||
{
|
|
||||||
"1": "X", "2": "", "3": "O",
|
|
||||||
"4": "X", "5": "O", "6": "",
|
|
||||||
"7": "", "8": "", "9": "",
|
|
||||||
"your_token": "X"
|
|
||||||
}
|
|
||||||
|
|
||||||
And you're expected to return a response of which field you'd like to
|
|
||||||
place your piece in. For example, if you wish to place your token in
|
|
||||||
field 7, your response should look like this:
|
|
||||||
|
|
||||||
{ "move": 7 }
|
|
||||||
|
|
||||||
The board is arranged as follows:
|
|
||||||
|
|
||||||
1 | 2 | 3
|
|
||||||
---+---+---
|
|
||||||
4 | 5 | 6
|
|
||||||
---+---+---
|
|
||||||
7 | 8 | 9
|
|
||||||
|
|
||||||
:param payload: The incoming JSON that contains the game state.
|
|
||||||
:type payload: dict[str, Any]
|
:type payload: dict[str, Any]
|
||||||
:return: The move you wish to take.
|
:return: The agent of chaos' random choice
|
||||||
:rtype: dict[str, Any]
|
:rtype: dict[str, Any]
|
||||||
"""
|
"""
|
||||||
|
options = [
|
||||||
# Try printing the payload to see what it looks like!
|
int(k)
|
||||||
print(payload)
|
for k, v in dict(payload).items()
|
||||||
|
if k in "0123456789" and v == ""
|
||||||
options = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, ]
|
]
|
||||||
|
|
||||||
# 1. Try filtering out the impossible moves!
|
|
||||||
# If an X or O was already placed at a field, remove it from the options
|
|
||||||
|
|
||||||
#
|
|
||||||
|
|
||||||
# 2. Try finding two in a row! If possible, you can try to place the third
|
|
||||||
# item on the board and get 3 in a row.
|
|
||||||
|
|
||||||
#
|
|
||||||
|
|
||||||
# 3. Perhaps you can block the opponent from getting 3 in a row?
|
|
||||||
|
|
||||||
#
|
|
||||||
|
|
||||||
# Now, pick any of the remaining options.
|
|
||||||
# This is just a simple implementation. Naturally, you're welcome to try
|
|
||||||
# your own logic.
|
|
||||||
return { "move": random.choice(options) }
|
return { "move": random.choice(options) }
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue