Skip to content

Commit

Permalink
fix: two way imports
Browse files Browse the repository at this point in the history
  • Loading branch information
Krasto committed Jan 18, 2024
1 parent 9ecf086 commit f96a4b7
Show file tree
Hide file tree
Showing 7 changed files with 84 additions and 31 deletions.
21 changes: 14 additions & 7 deletions ci_quixo/custom_game.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
from typing import TYPE_CHECKING
try:
from game import Game, Move
if TYPE_CHECKING:
from main import Player
except:
from .game import Game, Move
if TYPE_CHECKING:
from .main import Player

import numpy as np
from game import Game, Move
from collections import namedtuple, defaultdict
from copy import deepcopy
from typing import TYPE_CHECKING
from tqdm.auto import tqdm

if TYPE_CHECKING:
from main import Player
import pytest

Position = namedtuple("Position", ["x", "y"], defaults=[0, 0])
POSSIBLE_POSITIONS = tuple(
Expand Down Expand Up @@ -218,7 +224,8 @@ def simulate_move(self, move: "CompleteMove") -> "CustomGame":
return copy


def benchmark(number: int = 1_000) -> None:
@pytest.mark.benchmark
def test_benchmark_symmetries(number: int = 1_000) -> None:
import timeit
pbar = tqdm(range(3), unit="test", leave=False)
ff = timeit.timeit(stmt="it.valid_moves(None, False, False)", setup="from custom_game import CustomGame;it = CustomGame()", number=number)
Expand All @@ -236,4 +243,4 @@ def benchmark(number: int = 1_000) -> None:

if __name__ == "__main__":
from random import choice
benchmark()
test_benchmark_symmetries()
19 changes: 12 additions & 7 deletions ci_quixo/helper.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
import numpy as np
from typing import TYPE_CHECKING
from main import Move, RandomPlayer, Game
try:
from main import Move, RandomPlayer, Game, Player
from custom_game import CustomGame
if TYPE_CHECKING:
from custom_game import CompleteMove
except:
from .main import Move, RandomPlayer, Game, Player
from .custom_game import CustomGame
if TYPE_CHECKING:
from .custom_game import CompleteMove

import numpy as np
from tqdm.auto import trange
from custom_game import CustomGame
from main import Player
if TYPE_CHECKING:
from custom_game import CompleteMove
from game import Game

def pprint_board(game: "Game"):
board: np.ndarray = game.get_board()
Expand Down
5 changes: 4 additions & 1 deletion ci_quixo/main.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
# https://github.com/squillero/computational-intelligence/blob/master/2023-24/quixo/
import random
from game import Game, Move, Player
try:
from game import Game, Move, Player
except:
from .game import Game, Move, Player


class RandomPlayer(Player):
Expand Down
17 changes: 12 additions & 5 deletions ci_quixo/mcts.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,21 @@
from game import Game, Move, Player
from custom_game import CustomGame
from typing import TYPE_CHECKING, Literal
try:
from game import Game, Move, Player
from custom_game import CustomGame
if TYPE_CHECKING:
from custom_game import CompleteMove
except:
from .game import Game, Move, Player
from .custom_game import CustomGame
if TYPE_CHECKING:
from .custom_game import CompleteMove

import numpy as np, random
from dataclasses import dataclass, field
from collections import defaultdict
from copy import deepcopy
from typing import TYPE_CHECKING, Literal
import time
from tqdm.auto import trange, tqdm
if TYPE_CHECKING:
from custom_game import CompleteMove

# implementation inspired from https://github.com/aimacode/aima-python/blob/61d695b37c6895902081da1f37baf645b0d2658a/games4e.py#L178

Expand Down
31 changes: 25 additions & 6 deletions ci_quixo/minmax.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,30 @@
from game import Player, Game
from custom_game import CustomGame, POSSIBLE_MOVES
from typing import TYPE_CHECKING, Literal, Union
try:
from game import Player, Game
from custom_game import CustomGame, POSSIBLE_MOVES
if TYPE_CHECKING:
from custom_game import CompleteMove
except:
from .game import Player, Game
from .custom_game import CustomGame, POSSIBLE_MOVES
if TYPE_CHECKING:
from .custom_game import CompleteMove

import numpy as np
from collections import defaultdict
import random
import time

if TYPE_CHECKING:
from custom_game import CompleteMove


class MinMaxPlayer(Player):
""" Minimax Player with alpha-beta pruning (togglable) and a hash-table to store previously evaluated states.
There are 4 possible pruning 'levels' (explained in detail below), i believe the best tradeoff between pruning and speed is level 1,
going at a deeper level is just too much time wasted due to the time required to process the (ineffiently implemented) symmetries.
To have an understanding of the difference of time there is a bencharmking function that shows it (see `custom_game.test_benchmark_symmetries`), spoiler: +2400%
"""

def __init__(
self,
max_depth: int = 2,
Expand All @@ -20,7 +34,7 @@ def __init__(
htable: bool = True,

) -> None:
"""Minimax Player
"""Init
Args:
max_depth (int, optional): Tree depth. Defaults to 2.
Expand Down Expand Up @@ -235,8 +249,13 @@ def stats(self) -> dict[str, str]:
hitratio = self._stats["HTABLE-HIT"] / self._stats['HTABLE-MISS'] + self._stats['HTABLE-HIT']
pp["HashTable HitRatio"] = f"{hitratio:.3%}"
return pp

if __name__ == "__main__":
from helper import evaluate
try:
from helper import evaluate
except:
from .helper import evaluate

from pprint import pprint

mf = MinMaxPlayer(2, pruning=0, htable=False)
Expand Down
19 changes: 14 additions & 5 deletions ci_quixo/qlearning.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,19 @@
from custom_game import CustomGame, POSSIBLE_MOVES, CompleteMove
from game import Game, Move
try:
from custom_game import CustomGame, POSSIBLE_MOVES, CompleteMove
from game import Game, Move
from main import RandomPlayer, Player
except:
from .custom_game import CustomGame, POSSIBLE_MOVES, CompleteMove
from .game import Game, Move
from .main import RandomPlayer, Player

from copy import deepcopy
from collections import defaultdict
from main import Player
from typing import DefaultDict
from dataclasses import dataclass, field
from tqdm.auto import trange, tqdm
import random, dill
import numpy as np
from main import RandomPlayer

# QTable Structure
# [key: board hash (str)]: {
Expand All @@ -34,7 +39,11 @@ def clamp(value, min_, max_):

@dataclass
class QLearning(Player):

"""QLearning attempt
@deprecated Maybe there are still some bugs, I have not looked into it that much, but i believe it's not the right approach because
there are so many states and it needs A LOT of games to be able to learn and propagate it back (if it will ever)
"""

qtable: QTable = field(
default_factory=lambda: defaultdict(QLearning.__inner_defdict_builder)
)
Expand Down
3 changes: 3 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,6 @@ dill = "^0.3.7"
[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"

[tool.pytest.ini_options]
markers = ["benchmark", "evaluate"]

0 comments on commit f96a4b7

Please sign in to comment.