Create naive line counter for tic-tac-toe
parent
c004d9d3e7
commit
622cc55bb5
|
|
@ -0,0 +1,117 @@
|
||||||
|
"""
|
||||||
|
The naive line counter aims to calculate the best move by comparing the
|
||||||
|
lines and checking how many are filled.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import random
|
||||||
|
|
||||||
|
from .agent import Agent, Payload
|
||||||
|
|
||||||
|
|
||||||
|
class NaiveLineCounter(Agent):
|
||||||
|
"""
|
||||||
|
Tic-tac-toe has 8 possible lines where you can get 3 in a row.
|
||||||
|
|
||||||
|
For all 8 lines, count how many would benefit from the addition of a
|
||||||
|
single sign. In priority, count how many lines are added.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self) -> None:
|
||||||
|
super().__init__(
|
||||||
|
name="Naive line counter",
|
||||||
|
author="Bram",
|
||||||
|
version="1.0.0",
|
||||||
|
profile={},
|
||||||
|
)
|
||||||
|
|
||||||
|
self.add_tic_tac_toe(on_move=self.play_tic_tac_toe, profile={})
|
||||||
|
|
||||||
|
def play_tic_tac_toe(self, payload : Payload) -> Payload:
|
||||||
|
"""
|
||||||
|
For each line:
|
||||||
|
|
||||||
|
[X][X][_] -> 3 in a row
|
||||||
|
[O][O][_] -> ruin an opponent's 3 in a row
|
||||||
|
[X][_][ ] -> 2 in a row
|
||||||
|
[O][_][ ] -> ruin an opponent's 2 in a row
|
||||||
|
[_][ ][ ] -> 1 in a row
|
||||||
|
|
||||||
|
Count how many they occur, then sort based on priority.
|
||||||
|
"""
|
||||||
|
lines = [
|
||||||
|
[ 1, 2, 3, ],
|
||||||
|
[ 4, 5, 6, ],
|
||||||
|
[ 7, 8, 9, ],
|
||||||
|
|
||||||
|
[ 1, 4, 7, ],
|
||||||
|
[ 2, 5, 8, ],
|
||||||
|
[ 3, 6, 9, ],
|
||||||
|
|
||||||
|
[ 1, 5, 9, ],
|
||||||
|
[ 3, 5, 7, ],
|
||||||
|
]
|
||||||
|
|
||||||
|
my_piece = payload["your_token"]
|
||||||
|
moves, value = [], ( 0, 0, 0, 0, 0 )
|
||||||
|
|
||||||
|
for i in range(1, 10):
|
||||||
|
i_val = field_score(payload=payload, field=i, my_piece=my_piece)
|
||||||
|
|
||||||
|
if i_val > value:
|
||||||
|
moves, value = [i], i_val
|
||||||
|
elif i_val == value:
|
||||||
|
moves.append(i)
|
||||||
|
|
||||||
|
return dict(move=random.choice(moves))
|
||||||
|
|
||||||
|
def field_score(payload : Payload, field : int, my_piece : str) -> tuple[int, int, int, int, int]:
|
||||||
|
"""
|
||||||
|
Determine the score of a specific field in the grid.
|
||||||
|
"""
|
||||||
|
a, b, c, d, e = 0, 0, 0, 0, 0
|
||||||
|
lines = [
|
||||||
|
[ 1, 2, 3, ],
|
||||||
|
[ 4, 5, 6, ],
|
||||||
|
[ 7, 8, 9, ],
|
||||||
|
|
||||||
|
[ 1, 4, 7, ],
|
||||||
|
[ 2, 5, 8, ],
|
||||||
|
[ 3, 6, 9, ],
|
||||||
|
|
||||||
|
[ 1, 5, 9, ],
|
||||||
|
[ 3, 5, 7, ],
|
||||||
|
]
|
||||||
|
|
||||||
|
if payload[str(field)] != "":
|
||||||
|
return ( a, b, c, d, e )
|
||||||
|
|
||||||
|
for line in lines:
|
||||||
|
if field not in line:
|
||||||
|
continue
|
||||||
|
|
||||||
|
values = [ payload[str(f)] for f in line if field != f ]
|
||||||
|
x = values.count("X")
|
||||||
|
o = values.count("O")
|
||||||
|
|
||||||
|
s = ( x, o ) if my_piece == "X" else ( o, x )
|
||||||
|
match s:
|
||||||
|
case ( 2, 0 ):
|
||||||
|
a += 1
|
||||||
|
case ( 0, 2 ):
|
||||||
|
b += 1
|
||||||
|
case ( 1, 0 ):
|
||||||
|
c += 1
|
||||||
|
case ( 0, 1 ):
|
||||||
|
d += 1
|
||||||
|
case ( 0, 0 ):
|
||||||
|
e += 1
|
||||||
|
case ( 1, 1 ):
|
||||||
|
pass
|
||||||
|
case _:
|
||||||
|
raise ValueError(
|
||||||
|
f"Unknown number of items: {s}"
|
||||||
|
)
|
||||||
|
|
||||||
|
return ( a, b, c, d, e )
|
||||||
|
|
@ -6,6 +6,7 @@ from __future__ import annotations
|
||||||
|
|
||||||
import agents
|
import agents
|
||||||
|
|
||||||
|
from agents.naive_line_counter import NaiveLineCounter
|
||||||
from pyserver import PyServer
|
from pyserver import PyServer
|
||||||
|
|
||||||
def main() -> int:
|
def main() -> int:
|
||||||
|
|
@ -15,7 +16,7 @@ def main() -> int:
|
||||||
:return: Exit code
|
:return: Exit code
|
||||||
:rtype: int
|
:rtype: int
|
||||||
"""
|
"""
|
||||||
player = PyServer(agents.RemoteAgent(url="https://bmt001.noordstar.me/"))
|
player = PyServer(NaiveLineCounter())
|
||||||
|
|
||||||
# Start listening for games
|
# Start listening for games
|
||||||
player.start(
|
player.start(
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue