Compare commits
1 Commits
| Author | SHA1 | Date |
|---|---|---|
|
|
e9a25c37e1 |
9
elo.py
9
elo.py
|
|
@ -5,6 +5,9 @@
|
||||||
from elo_tracker import EloTracker
|
from elo_tracker import EloTracker
|
||||||
from pyclient.games import TicTacToe
|
from pyclient.games import TicTacToe
|
||||||
|
|
||||||
|
import pyclient
|
||||||
|
import time
|
||||||
|
|
||||||
GAME_FILE = "games.jsonl"
|
GAME_FILE = "games.jsonl"
|
||||||
PLAYER_FILE = "known_players.json"
|
PLAYER_FILE = "known_players.json"
|
||||||
|
|
||||||
|
|
@ -17,14 +20,14 @@ def main() -> int:
|
||||||
|
|
||||||
tracker.start_periodic_matches(
|
tracker.start_periodic_matches(
|
||||||
game=TicTacToe.empty(),
|
game=TicTacToe.empty(),
|
||||||
interval_seconds=10 * 60,
|
interval_seconds=60,
|
||||||
player_count=2,
|
player_count=2,
|
||||||
)
|
)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
tracker.start_server(import_name=__name__)
|
while True:
|
||||||
|
pass
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
print("Noticed KeyboardInterrupt, stopping match daemon...")
|
|
||||||
tracker.stop_periodic_matches()
|
tracker.stop_periodic_matches()
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
|
|
|
||||||
|
|
@ -206,7 +206,7 @@ class Match:
|
||||||
|
|
||||||
participants : list[tuple[PlayerIdentifier, FinishState]] = []
|
participants : list[tuple[PlayerIdentifier, FinishState]] = []
|
||||||
for i, agent in enumerate(players):
|
for i, agent in enumerate(players):
|
||||||
finish_state = results.get(i + 1, None)
|
finish_state = results.get(i, None)
|
||||||
if finish_state is None:
|
if finish_state is None:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
|
@ -395,9 +395,6 @@ class EloTracker:
|
||||||
rating_1 = self.__get_stat(player_id=player_id1).elo
|
rating_1 = self.__get_stat(player_id=player_id1).elo
|
||||||
|
|
||||||
for player_id2, result2 in m.participants:
|
for player_id2, result2 in m.participants:
|
||||||
if player_id1 == player_id2:
|
|
||||||
continue
|
|
||||||
|
|
||||||
rating_2 = self.__get_stat(player_id=player_id2).elo
|
rating_2 = self.__get_stat(player_id=player_id2).elo
|
||||||
|
|
||||||
expected_score = 1 / (1 + 10 ** ((rating_2 - rating_1) / STD_DEV_DIFF))
|
expected_score = 1 / (1 + 10 ** ((rating_2 - rating_1) / STD_DEV_DIFF))
|
||||||
|
|
@ -586,7 +583,7 @@ class EloTracker:
|
||||||
:rtype: pyclient.GameReplay
|
:rtype: pyclient.GameReplay
|
||||||
:raises ValueError: One of the URLs could not be accessed.
|
:raises ValueError: One of the URLs could not be accessed.
|
||||||
"""
|
"""
|
||||||
agents : list[Any] = [
|
agents = [
|
||||||
pyclient.Agent.from_url(url, debug=self.debug)
|
pyclient.Agent.from_url(url, debug=self.debug)
|
||||||
for url in players
|
for url in players
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
{
|
{
|
||||||
"players": [
|
"players": [
|
||||||
"https://bmt001.noordstar.me",
|
"https://bmt001.noordstar.me"
|
||||||
"https://bmt002.noordstar.me"
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
69
server.py
69
server.py
|
|
@ -18,17 +18,23 @@ def main() -> int:
|
||||||
"""
|
"""
|
||||||
player = PyServer(
|
player = PyServer(
|
||||||
# Customize this to whatever you'd like to call your player
|
# Customize this to whatever you'd like to call your player
|
||||||
name="My super smart robot player",
|
name="Mute",
|
||||||
|
|
||||||
# Custom information that you can use to tell people about this player
|
# Custom information that you can use to tell people about this player
|
||||||
profile={},
|
profile={
|
||||||
|
"me.noordstar.peanuts.agent.version": "1.0.0",
|
||||||
|
"me.noordstar.peanuts.is_ai": False,
|
||||||
|
"me.noordstar.peanuts.author": "Bram",
|
||||||
|
"me.noordstar.peanuts.containerized": True,
|
||||||
|
"version": "1.0.0",
|
||||||
|
},
|
||||||
|
|
||||||
# Unless you know what you're doing, don't touch this.
|
# 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.
|
# 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=respond_mute, profile={})
|
||||||
|
|
||||||
# Start listening for games
|
# Start listening for games
|
||||||
player.start(
|
player.start(
|
||||||
|
|
@ -38,62 +44,19 @@ def main() -> int:
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
def play_tic_tac_toe(payload : dict[str, Any]) -> dict[str, Any]:
|
def respond_mute(payload : dict[str, Any]) -> dict[str, Any]:
|
||||||
"""
|
"""
|
||||||
Play a game of tic-tac-toe.
|
Always respond with an empty dictionary. This means the user should
|
||||||
|
always take the "default" move.
|
||||||
|
|
||||||
You receive a payload that looks like this:
|
A well-programmed game must NOT raise an error as a result of this.
|
||||||
|
|
||||||
{
|
:param payload: The game state which is completely ignored.
|
||||||
"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: An empty dictionary
|
||||||
:rtype: dict[str, Any]
|
:rtype: dict[str, Any]
|
||||||
"""
|
"""
|
||||||
|
return {}
|
||||||
# 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__":
|
if __name__ == "__main__":
|
||||||
raise SystemExit(main())
|
raise SystemExit(main())
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue