agents.base_agent

 1import json
 2import logging
 3from typing import List, Optional, Tuple, Union
 4
 5import websockets
 6
 7logging.basicConfig(level=logging.INFO, format="%(asctime)s - AGENT - %(message)s")
 8
 9
10class BaseUTTTAgent:
11    """
12    Abstract base class for all Ultimate Tic-Tac-Toe agents.
13    The game is played on a $9 \times 9$ micro-board, divided into $3 \times 3$ macro-boards.
14    """
15
16    def __init__(self, server_uri: str = "ws://localhost:8765") -> None:
17        """
18        Initializes the BaseUTTTAgent.
19
20        Args:
21            server_uri (str): The URI of the UTTT server.
22        """
23        self.server_uri: str = server_uri
24        self.player_id: Optional[int] = None
25
26    async def run(self) -> None:
27        """
28        Connects to the server and enters the main communication loop.
29        """
30        try:
31            async with websockets.connect(self.server_uri) as websocket:
32                await websocket.send(json.dumps({"client": "agent"}))
33
34                async for message in websocket:
35                    if isinstance(message, bytes):
36                        message = message.decode("utf-8")
37                    data = json.loads(message)
38
39                    if data.get("type") == "setup":
40                        self.player_id = data.get("player_id")
41                        logging.info(f"Connected! Assigned Player {self.player_id}")
42
43                    elif data.get("type") == "state":
44                        current_turn = data.get("current_turn")
45                        board = data.get("board")
46                        macro_board = data.get("macro_board")
47                        active_macro = data.get("active_macro")
48                        valid_actions = data.get("valid_actions")
49
50                        if current_turn == self.player_id:
51                            action = await self.deliberate(
52                                board, macro_board, active_macro, valid_actions
53                            )
54
55                            if action is not None:
56                                await websocket.send(
57                                    json.dumps(
58                                        {
59                                            "action": "move",
60                                            "x": action[0],
61                                            "y": action[1],
62                                        }
63                                    )
64                                )
65
66                    elif data.get("type") == "game_over":
67                        logging.info(f"Match Over: {data.get('message')}")
68
69        except Exception as e:
70            logging.error(f"Connection lost: {e}")
71
72    async def deliberate(
73        self,
74        board: List[List[int]],
75        macro_board: List[List[int]],
76        active_macro: Optional[List[int]],
77        valid_actions: List[List[int]],
78    ) -> Optional[Union[List[int], Tuple[int, int]]]:
79        """
80        Deliberates on the next move. MUST be implemented by subclasses.
81
82        Args:
83            board (List[List[int]]): The current 9x9 board state.
84            macro_board (List[List[int]]): The current 3x3 macro board state.
85            active_macro (Optional[List[int]]): The active macro board coordinates [my, mx].
86            valid_actions (List[List[int]]): A list of valid moves [x, y].
87
88        Returns:
89            Optional[Union[List[int], Tuple[int, int]]]: The chosen move [x, y] or None.
90        """
91        raise NotImplementedError("Subclasses must implement deliberate()")
class BaseUTTTAgent:
11class BaseUTTTAgent:
12    """
13    Abstract base class for all Ultimate Tic-Tac-Toe agents.
14    The game is played on a $9 \times 9$ micro-board, divided into $3 \times 3$ macro-boards.
15    """
16
17    def __init__(self, server_uri: str = "ws://localhost:8765") -> None:
18        """
19        Initializes the BaseUTTTAgent.
20
21        Args:
22            server_uri (str): The URI of the UTTT server.
23        """
24        self.server_uri: str = server_uri
25        self.player_id: Optional[int] = None
26
27    async def run(self) -> None:
28        """
29        Connects to the server and enters the main communication loop.
30        """
31        try:
32            async with websockets.connect(self.server_uri) as websocket:
33                await websocket.send(json.dumps({"client": "agent"}))
34
35                async for message in websocket:
36                    if isinstance(message, bytes):
37                        message = message.decode("utf-8")
38                    data = json.loads(message)
39
40                    if data.get("type") == "setup":
41                        self.player_id = data.get("player_id")
42                        logging.info(f"Connected! Assigned Player {self.player_id}")
43
44                    elif data.get("type") == "state":
45                        current_turn = data.get("current_turn")
46                        board = data.get("board")
47                        macro_board = data.get("macro_board")
48                        active_macro = data.get("active_macro")
49                        valid_actions = data.get("valid_actions")
50
51                        if current_turn == self.player_id:
52                            action = await self.deliberate(
53                                board, macro_board, active_macro, valid_actions
54                            )
55
56                            if action is not None:
57                                await websocket.send(
58                                    json.dumps(
59                                        {
60                                            "action": "move",
61                                            "x": action[0],
62                                            "y": action[1],
63                                        }
64                                    )
65                                )
66
67                    elif data.get("type") == "game_over":
68                        logging.info(f"Match Over: {data.get('message')}")
69
70        except Exception as e:
71            logging.error(f"Connection lost: {e}")
72
73    async def deliberate(
74        self,
75        board: List[List[int]],
76        macro_board: List[List[int]],
77        active_macro: Optional[List[int]],
78        valid_actions: List[List[int]],
79    ) -> Optional[Union[List[int], Tuple[int, int]]]:
80        """
81        Deliberates on the next move. MUST be implemented by subclasses.
82
83        Args:
84            board (List[List[int]]): The current 9x9 board state.
85            macro_board (List[List[int]]): The current 3x3 macro board state.
86            active_macro (Optional[List[int]]): The active macro board coordinates [my, mx].
87            valid_actions (List[List[int]]): A list of valid moves [x, y].
88
89        Returns:
90            Optional[Union[List[int], Tuple[int, int]]]: The chosen move [x, y] or None.
91        """
92        raise NotImplementedError("Subclasses must implement deliberate()")

Abstract base class for all Ultimate Tic-Tac-Toe agents. The game is played on a $9 imes 9$ micro-board, divided into $3 imes 3$ macro-boards.

BaseUTTTAgent(server_uri: str = 'ws://localhost:8765')
17    def __init__(self, server_uri: str = "ws://localhost:8765") -> None:
18        """
19        Initializes the BaseUTTTAgent.
20
21        Args:
22            server_uri (str): The URI of the UTTT server.
23        """
24        self.server_uri: str = server_uri
25        self.player_id: Optional[int] = None

Initializes the BaseUTTTAgent.

Args: server_uri (str): The URI of the UTTT server.

server_uri: str
player_id: Optional[int]
async def run(self) -> None:
27    async def run(self) -> None:
28        """
29        Connects to the server and enters the main communication loop.
30        """
31        try:
32            async with websockets.connect(self.server_uri) as websocket:
33                await websocket.send(json.dumps({"client": "agent"}))
34
35                async for message in websocket:
36                    if isinstance(message, bytes):
37                        message = message.decode("utf-8")
38                    data = json.loads(message)
39
40                    if data.get("type") == "setup":
41                        self.player_id = data.get("player_id")
42                        logging.info(f"Connected! Assigned Player {self.player_id}")
43
44                    elif data.get("type") == "state":
45                        current_turn = data.get("current_turn")
46                        board = data.get("board")
47                        macro_board = data.get("macro_board")
48                        active_macro = data.get("active_macro")
49                        valid_actions = data.get("valid_actions")
50
51                        if current_turn == self.player_id:
52                            action = await self.deliberate(
53                                board, macro_board, active_macro, valid_actions
54                            )
55
56                            if action is not None:
57                                await websocket.send(
58                                    json.dumps(
59                                        {
60                                            "action": "move",
61                                            "x": action[0],
62                                            "y": action[1],
63                                        }
64                                    )
65                                )
66
67                    elif data.get("type") == "game_over":
68                        logging.info(f"Match Over: {data.get('message')}")
69
70        except Exception as e:
71            logging.error(f"Connection lost: {e}")

Connects to the server and enters the main communication loop.

async def deliberate( self, board: List[List[int]], macro_board: List[List[int]], active_macro: Optional[List[int]], valid_actions: List[List[int]]) -> Union[List[int], Tuple[int, int], NoneType]:
73    async def deliberate(
74        self,
75        board: List[List[int]],
76        macro_board: List[List[int]],
77        active_macro: Optional[List[int]],
78        valid_actions: List[List[int]],
79    ) -> Optional[Union[List[int], Tuple[int, int]]]:
80        """
81        Deliberates on the next move. MUST be implemented by subclasses.
82
83        Args:
84            board (List[List[int]]): The current 9x9 board state.
85            macro_board (List[List[int]]): The current 3x3 macro board state.
86            active_macro (Optional[List[int]]): The active macro board coordinates [my, mx].
87            valid_actions (List[List[int]]): A list of valid moves [x, y].
88
89        Returns:
90            Optional[Union[List[int], Tuple[int, int]]]: The chosen move [x, y] or None.
91        """
92        raise NotImplementedError("Subclasses must implement deliberate()")

Deliberates on the next move. MUST be implemented by subclasses.

Args: board (List[List[int]]): The current 9x9 board state. macro_board (List[List[int]]): The current 3x3 macro board state. active_macro (Optional[List[int]]): The active macro board coordinates [my, mx]. valid_actions (List[List[int]]): A list of valid moves [x, y].

Returns: Optional[Union[List[int], Tuple[int, int]]]: The chosen move [x, y] or None.