Create client script with diagnostics
parent
eb5a869cf4
commit
78c461d9b2
|
|
@ -0,0 +1,87 @@
|
||||||
|
"""
|
||||||
|
This module offers a small place to start building game clients from.
|
||||||
|
|
||||||
|
You can use this for:
|
||||||
|
|
||||||
|
- Learning how the system works.
|
||||||
|
- Debugging a game server.
|
||||||
|
- Debugging a game that behaves weirdly.
|
||||||
|
|
||||||
|
This module lets you host a game, let online servers participate in it,
|
||||||
|
and then analyze the outcome.
|
||||||
|
|
||||||
|
|
||||||
|
You can build several things with this:
|
||||||
|
|
||||||
|
1. You can build an AI trainer that trains on existing players.
|
||||||
|
2. You can build an ELO evaluator that compares the performance of various
|
||||||
|
strategies.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import json
|
||||||
|
|
||||||
|
from pyclient import PyClient
|
||||||
|
from pyclient.games.tic_tac_toe import TicTacToe
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
def main() -> int:
|
||||||
|
"""
|
||||||
|
Start a client, then use it to analyze one or more matches.
|
||||||
|
|
||||||
|
:return: Exit code
|
||||||
|
:rtype: int
|
||||||
|
"""
|
||||||
|
c = PyClient([
|
||||||
|
"https://bmt001.noordstar.me",
|
||||||
|
"https://bmt001.noordstar.me",
|
||||||
|
], debug=False)
|
||||||
|
|
||||||
|
out = c.play_game("tic-tac-toe", TicTacToe)
|
||||||
|
|
||||||
|
inspect_game(out)
|
||||||
|
|
||||||
|
return 0
|
||||||
|
|
||||||
|
def inspect_game(game : list[tuple[int, dict[str, Any], Any]]) -> None:
|
||||||
|
"""
|
||||||
|
Print a diagnostic of a played game to the terminal.
|
||||||
|
|
||||||
|
:param game: The results of a played game.
|
||||||
|
:type game: list[typle[int, dict[str, Any], Any]]
|
||||||
|
"""
|
||||||
|
max_width = 40
|
||||||
|
hbar = max_width * '%'
|
||||||
|
|
||||||
|
def title(s : str) -> None:
|
||||||
|
"""
|
||||||
|
Show a title nice and clean in the middle
|
||||||
|
|
||||||
|
:param s: The title to display
|
||||||
|
:type s: str
|
||||||
|
"""
|
||||||
|
w = (max_width - len(s)) // 2
|
||||||
|
|
||||||
|
print(hbar)
|
||||||
|
print((w * ' ') + s.upper() + (w * ' '))
|
||||||
|
print(hbar)
|
||||||
|
|
||||||
|
# Show all moves made throughout the game
|
||||||
|
title("Turns taken")
|
||||||
|
for player, action, _ in game:
|
||||||
|
print(f"Player {player} : " + json.dumps(action)[:max_width-12])
|
||||||
|
|
||||||
|
# Show all remaining variables in the finishing state of the game
|
||||||
|
title("Final state")
|
||||||
|
final_state = game[-1][2]
|
||||||
|
for k, v in final_state.to_dict().items():
|
||||||
|
print(f"{k} => {json.dumps(v)}")
|
||||||
|
|
||||||
|
# Some final (usually the most relevant) statistics
|
||||||
|
title("Result")
|
||||||
|
print(f"Total turns taken: {len(game)}")
|
||||||
|
print("Winner: " + ("0 (tie)" if final_state.winner() == 0 else f"player {final_state.winner()}"))
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
raise SystemExit(main())
|
||||||
89
main.py
89
main.py
|
|
@ -1,89 +0,0 @@
|
||||||
"""
|
|
||||||
This module enables a user to host a server that is able to play games.
|
|
||||||
"""
|
|
||||||
|
|
||||||
import random
|
|
||||||
|
|
||||||
from pyserver import PyServer
|
|
||||||
from pyclient import PyClient
|
|
||||||
from pyclient.games.tic_tac_toe import TicTacToe
|
|
||||||
|
|
||||||
def main():
|
|
||||||
player = PyServer(
|
|
||||||
# Customize this to whatever you'd like to call your player
|
|
||||||
name="My super smart robot player",
|
|
||||||
|
|
||||||
# Custom information that you can use to tell people about this player
|
|
||||||
profile={},
|
|
||||||
|
|
||||||
# Unless you know what you're doing, don't touch this.
|
|
||||||
import_name=__name__,
|
|
||||||
)
|
|
||||||
|
|
||||||
player.add_tic_tac_toe(on_move=play_tic_tac_toe, profile={})
|
|
||||||
|
|
||||||
player.start(port=5001)
|
|
||||||
|
|
||||||
return 0
|
|
||||||
|
|
||||||
def play_tic_tac_toe(payload):
|
|
||||||
"""
|
|
||||||
Play a game of tic-tac-toe.
|
|
||||||
|
|
||||||
You receive a payload that looks like this:
|
|
||||||
|
|
||||||
{
|
|
||||||
"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
|
|
||||||
"""
|
|
||||||
|
|
||||||
# Try printing the payload to see what it looks like!
|
|
||||||
print(payload)
|
|
||||||
|
|
||||||
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) }
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
raise SystemExit(main())
|
|
||||||
|
|
||||||
c = PyClient([
|
|
||||||
"http://127.0.0.1:5001",
|
|
||||||
"http://127.0.0.1:5002",
|
|
||||||
], debug=True)
|
|
||||||
|
|
||||||
out = c.play_game("tic-tac-toe", TicTacToe)
|
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
certifi==2026.6.17
|
||||||
|
charset-normalizer==3.4.7
|
||||||
|
idna==3.18
|
||||||
|
requests==2.34.2
|
||||||
|
urllib3==2.7.0
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
blinker==1.9.0
|
blinker==1.9.0
|
||||||
certifi==2026.5.20
|
certifi==2026.6.17
|
||||||
charset-normalizer==3.4.7
|
charset-normalizer==3.4.7
|
||||||
click==8.4.1
|
click==8.4.1
|
||||||
colorama==0.4.6
|
colorama==0.4.6
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue