From d2d1e5615cb01426d5efc4c9a600a68e651e50fa Mon Sep 17 00:00:00 2001 From: Michael Conard Date: Thu, 23 Nov 2023 17:49:30 -0500 Subject: [PATCH 01/12] support SmallestPieceEngine --- example_tournament.py | 7 ++++--- tilewe/__init__.py | 5 +++++ tilewe/engine.py | 16 ++++++++++------ 3 files changed, 19 insertions(+), 9 deletions(-) diff --git a/example_tournament.py b/example_tournament.py index 4ed0339..8c47a6a 100644 --- a/example_tournament.py +++ b/example_tournament.py @@ -8,13 +8,14 @@ def run_tournament(): tournament = tilewe.tournament.Tournament([ tilewe.engine.MaximizeMoveDifferenceEngine(), tilewe.engine.LargestPieceEngine(), + tilewe.engine.LargestPieceEngine("SmallestPiece", True), tilewe.engine.TileWeightEngine("WallCrawler", 'wall_crawl'), tilewe.engine.TileWeightEngine("Turtle", 'turtle'), tilewe.engine.MostOpenCornersEngine(), tilewe.engine.RandomEngine(), ]) - results = tournament.play(100, n_threads=multiprocessing.cpu_count(), move_seconds=15) + results = tournament.play(5000, n_threads=multiprocessing.cpu_count(), move_seconds=15) # print the result of game 1 print(results.match_data[0].board) @@ -23,9 +24,9 @@ def run_tournament(): print(f"Tournament ran for {round(results.real_time, 4)}s with avg " + f"match duration {round(results.average_match_duration, 4)}s\n") - # print the engine rankings sorted by win_counts desc and then by avg_scores asc + # print the engine rankings sorted by win_counts desc and then by elo_error_margin desc print(results.get_engine_rankings_display('win_counts', 'desc')) - print(results.get_engine_rankings_display('avg_scores', 'asc')) + print(results.get_engine_rankings_display('elo_error_margin', 'desc')) if __name__ == '__main__': run_tournament() diff --git a/tilewe/__init__.py b/tilewe/__init__.py index 7d94874..b2717e5 100644 --- a/tilewe/__init__.py +++ b/tilewe/__init__.py @@ -249,3 +249,8 @@ def is_legal(self, move: Move, for_player: Color=None) -> bool: ] from ctilewe import * # noqa: E402, F401, F403 + +PIECE_TILES: list[int] = [n_piece_tiles(piece) for piece in range(NO_PIECE)] +PIECE_CORNERS: list[int] = [n_piece_corners(piece) for piece in range(NO_PIECE)] +PIECE_CONTACTS: list[int] = [n_piece_contacts(piece) for piece in range(NO_PIECE)] + diff --git a/tilewe/engine.py b/tilewe/engine.py index 769d3d2..b5a1b33 100644 --- a/tilewe/engine.py +++ b/tilewe/engine.py @@ -110,11 +110,15 @@ class LargestPieceEngine(Engine): Piece that has the most contacts Moderately strong from a greedy point hungry perspective. Since ties are common and result in a random move choice across the - ties, it's effectively a greedy form of RandomEngine. + ties, it's effectively a greedy form of RandomEngine. With the + inverse argument set, it becomes a SmallestPieceEngine. """ - def __init__(self, name: str="LargestPiece", estimated_elo: float=None): - super().__init__(name, 30.0 if estimated_elo is None else estimated_elo) + def __init__(self, name: str="LargestPiece", inverse: bool=False, estimated_elo: float=None): + if estimated_elo is None: + estimated_elo = -120.0 if inverse else 30.0 + super().__init__(name, estimated_elo) + self.mult = -1 if inverse else 1 def on_search(self, board: tilewe.Board, _seconds: float) -> tilewe.Move: moves = board.generate_legal_moves() @@ -122,9 +126,9 @@ def on_search(self, board: tilewe.Board, _seconds: float) -> tilewe.Move: def score(m: tilewe.Move): pc = tilewe.move_piece(m) - return tilewe.n_piece_tiles(pc) * 100 + \ - tilewe.n_piece_corners(pc) * 10 + \ - tilewe.n_piece_contacts(pc) + return self.mult * (tilewe.PIECE_TILES[pc] * 100 + + tilewe.PIECE_CORNERS[pc] * 10 + + tilewe.PIECE_CONTACTS[pc]) best = max(moves, key=score) From 5057cc169cb2677f7f33907b1c2e5eefe5a19dbc Mon Sep 17 00:00:00 2001 From: Michael Conard Date: Thu, 23 Nov 2023 19:26:52 -0500 Subject: [PATCH 02/12] add minimizer optiom for sample bots --- example_tournament.py | 10 ++++++---- tilewe/engine.py | 46 ++++++++++++++++++++++++++++--------------- 2 files changed, 36 insertions(+), 20 deletions(-) diff --git a/example_tournament.py b/example_tournament.py index 8c47a6a..8bf3efd 100644 --- a/example_tournament.py +++ b/example_tournament.py @@ -6,12 +6,14 @@ def run_tournament(): tournament = tilewe.tournament.Tournament([ - tilewe.engine.MaximizeMoveDifferenceEngine(), - tilewe.engine.LargestPieceEngine(), - tilewe.engine.LargestPieceEngine("SmallestPiece", True), + tilewe.engine.MoveDifferenceEngine("MaxMoveDiff", "max"), + tilewe.engine.MoveDifferenceEngine("MinMoveDiff", "min"), + tilewe.engine.PieceSizeEngine("LargestPiece", "max"), + tilewe.engine.PieceSizeEngine("SmallestPiece", "min"), tilewe.engine.TileWeightEngine("WallCrawler", 'wall_crawl'), tilewe.engine.TileWeightEngine("Turtle", 'turtle'), - tilewe.engine.MostOpenCornersEngine(), + tilewe.engine.OpenCornersEngine("MostOpenCorners", "max"), + tilewe.engine.OpenCornersEngine("LeastOpenCorners", "min"), tilewe.engine.RandomEngine(), ]) diff --git a/tilewe/engine.py b/tilewe/engine.py index b5a1b33..fccd221 100644 --- a/tilewe/engine.py +++ b/tilewe/engine.py @@ -78,7 +78,7 @@ def __init__(self, name: str="Random", estimated_elo: float=None): def on_search(self, board: tilewe.Board, _seconds: float) -> tilewe.Move: return random.choice(board.generate_legal_moves()) -class MostOpenCornersEngine(Engine): +class OpenCornersEngine(Engine): """ Plays the move that results in the player having the most playable corners possible afterwards, i.e. maximizing the @@ -86,8 +86,14 @@ class MostOpenCornersEngine(Engine): Fairly weak but does result in decent board coverage behavior. """ - def __init__(self, name: str="MostOpenCorners", estimated_elo: float=None): - super().__init__(name, 15.0 if estimated_elo is None else estimated_elo) + def __init__(self, name: str="MostOpenCorners", style: str="max", estimated_elo: float=None): + if style not in ["max", "min"]: + raise ValueError("Invalid style, must be 'max' or 'min'") + if estimated_elo is None: + estimated_elo = -120.0 if style == "min" else 15.0 + self.func = min if style == "min" else max + + super().__init__(name, estimated_elo) def on_search(self, board: tilewe.Board, _seconds: float) -> tilewe.Move: moves = board.generate_legal_moves() @@ -100,9 +106,9 @@ def corners_after_move(m: tilewe.Move) -> int: corners = board.n_player_corners(player) return corners - return max(moves, key=corners_after_move) + return self.func(moves, key=corners_after_move) -class LargestPieceEngine(Engine): +class PieceSizeEngine(Engine): """ Plays the best legal move prioritizing the following, in order: Piece with the most squares (i.e. most points) @@ -110,15 +116,17 @@ class LargestPieceEngine(Engine): Piece that has the most contacts Moderately strong from a greedy point hungry perspective. Since ties are common and result in a random move choice across the - ties, it's effectively a greedy form of RandomEngine. With the - inverse argument set, it becomes a SmallestPieceEngine. + ties, it's effectively a greedy form of RandomEngine. """ - def __init__(self, name: str="LargestPiece", inverse: bool=False, estimated_elo: float=None): + def __init__(self, name: str="LargestPiece", style: str="max", estimated_elo: float=None): + if style not in ["max", "min"]: + raise ValueError("Invalid style, must be 'max' or 'min'") if estimated_elo is None: - estimated_elo = -120.0 if inverse else 30.0 + estimated_elo = -120.0 if style == "min" else 30.0 + self.func = min if style == "min" else max + super().__init__(name, estimated_elo) - self.mult = -1 if inverse else 1 def on_search(self, board: tilewe.Board, _seconds: float) -> tilewe.Move: moves = board.generate_legal_moves() @@ -126,15 +134,15 @@ def on_search(self, board: tilewe.Board, _seconds: float) -> tilewe.Move: def score(m: tilewe.Move): pc = tilewe.move_piece(m) - return self.mult * (tilewe.PIECE_TILES[pc] * 100 + + return (tilewe.PIECE_TILES[pc] * 100 + tilewe.PIECE_CORNERS[pc] * 10 + tilewe.PIECE_CONTACTS[pc]) - best = max(moves, key=score) + best = self.func(moves, key=score) return best -class MaximizeMoveDifferenceEngine(Engine): +class MoveDifferenceEngine(Engine): """ Plays the move that results in the player having the best difference in subsequent legal move counts compared to all opponents. That is, @@ -145,8 +153,14 @@ class MaximizeMoveDifferenceEngine(Engine): getting access to an open area on the board, etc. """ - def __init__(self, name: str="MaximizeMoveDifference", estimated_elo: float=None): - super().__init__(name, 50.0 if estimated_elo is None else estimated_elo) + def __init__(self, name: str="MaxMoveDiff", style: str="max", estimated_elo: float=None): + if style not in ["max", "min"]: + raise ValueError("Invalid style, must be 'max' or 'min'") + if estimated_elo is None: + -100.0 if style == "min" else 50.0 + self.func = min if style == "min" else max + + super().__init__(name, estimated_elo) def on_search(self, board: tilewe.Board, _seconds: float) -> tilewe.Move: moves = board.generate_legal_moves() @@ -163,7 +177,7 @@ def eval_after_move(m: tilewe.Move) -> int: total += n_moves * (1 if color == player else -1) return total - return max(moves, key=eval_after_move) + return self.func(moves, key=eval_after_move) class TileWeightEngine(Engine): """ From 426bb4256bc2bf3bb84fa898f8eeb2009d5fa8f9 Mon Sep 17 00:00:00 2001 From: Michael Conard Date: Fri, 24 Nov 2023 01:28:55 -0500 Subject: [PATCH 03/12] update elo estimates --- example_tournament.py | 4 ++-- tilewe/engine.py | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/example_tournament.py b/example_tournament.py index 3880e9e..caa6715 100644 --- a/example_tournament.py +++ b/example_tournament.py @@ -26,9 +26,9 @@ def run_tournament(): print(f"Tournament ran for {round(results.real_time, 4)}s with avg " + f"match duration {round(results.average_match_duration, 4)}s\n") - # print the engine rankings sorted by win_counts desc and then by elo_error_margin desc + # print the engine rankings sorted by win_counts desc and then by elo_error_margin asc print(results.get_engine_rankings_display('win_counts', 'desc')) - print(results.get_engine_rankings_display('elo_error_margin', 'desc')) + print(results.get_engine_rankings_display('elo_error_margin', 'asc')) if __name__ == '__main__': run_tournament() diff --git a/tilewe/engine.py b/tilewe/engine.py index fccd221..e2ad35c 100644 --- a/tilewe/engine.py +++ b/tilewe/engine.py @@ -90,7 +90,7 @@ def __init__(self, name: str="MostOpenCorners", style: str="max", estimated_elo: if style not in ["max", "min"]: raise ValueError("Invalid style, must be 'max' or 'min'") if estimated_elo is None: - estimated_elo = -120.0 if style == "min" else 15.0 + estimated_elo = -250.0 if style == "min" else 15.0 self.func = min if style == "min" else max super().__init__(name, estimated_elo) @@ -123,7 +123,7 @@ def __init__(self, name: str="LargestPiece", style: str="max", estimated_elo: fl if style not in ["max", "min"]: raise ValueError("Invalid style, must be 'max' or 'min'") if estimated_elo is None: - estimated_elo = -120.0 if style == "min" else 30.0 + estimated_elo = -150.0 if style == "min" else 30.0 self.func = min if style == "min" else max super().__init__(name, estimated_elo) @@ -157,7 +157,7 @@ def __init__(self, name: str="MaxMoveDiff", style: str="max", estimated_elo: flo if style not in ["max", "min"]: raise ValueError("Invalid style, must be 'max' or 'min'") if estimated_elo is None: - -100.0 if style == "min" else 50.0 + -200.0 if style == "min" else 50.0 self.func = min if style == "min" else max super().__init__(name, estimated_elo) From 8d061641a341c450af86a11001d24656ec2c062c Mon Sep 17 00:00:00 2001 From: Nicholas Hamilton Date: Fri, 24 Nov 2023 01:23:08 -0600 Subject: [PATCH 04/12] Assign move difference engine estimated Elo based on style --- tilewe/engine.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tilewe/engine.py b/tilewe/engine.py index e2ad35c..a88c669 100644 --- a/tilewe/engine.py +++ b/tilewe/engine.py @@ -157,7 +157,7 @@ def __init__(self, name: str="MaxMoveDiff", style: str="max", estimated_elo: flo if style not in ["max", "min"]: raise ValueError("Invalid style, must be 'max' or 'min'") if estimated_elo is None: - -200.0 if style == "min" else 50.0 + estimated_elo = -200.0 if style == "min" else 50.0 self.func = min if style == "min" else max super().__init__(name, estimated_elo) From 1f39f5ad54308d79f258b61df897d6fb2de030b2 Mon Sep 17 00:00:00 2001 From: Michael Conard Date: Mon, 27 Nov 2023 21:58:21 -0500 Subject: [PATCH 05/12] change name handling --- example_tournament.py | 25 ++++++++++++++----------- tilewe/engine.py | 19 +++++++++++-------- 2 files changed, 25 insertions(+), 19 deletions(-) diff --git a/example_tournament.py b/example_tournament.py index caa6715..2d251b5 100644 --- a/example_tournament.py +++ b/example_tournament.py @@ -6,29 +6,32 @@ def run_tournament(): tournament = tilewe.tournament.Tournament([ - tilewe.engine.MoveDifferenceEngine("MaxMoveDiff", "max"), - tilewe.engine.MoveDifferenceEngine("MinMoveDiff", "min"), - tilewe.engine.PieceSizeEngine("LargestPiece", "max"), - tilewe.engine.PieceSizeEngine("SmallestPiece", "min"), + tilewe.engine.MoveDifferenceEngine(style="max"), + tilewe.engine.MoveDifferenceEngine(style="min"), + tilewe.engine.PieceSizeEngine(style="max"), + tilewe.engine.PieceSizeEngine(style="min"), tilewe.engine.TileWeightEngine("WallCrawler", 'wall_crawl'), tilewe.engine.TileWeightEngine("Turtle", 'turtle'), - tilewe.engine.OpenCornersEngine("MostOpenCorners", "max"), - tilewe.engine.OpenCornersEngine("LeastOpenCorners", "min"), - tilewe.engine.RandomEngine(), + tilewe.engine.OpenCornersEngine(style="max"), + tilewe.engine.OpenCornersEngine(style="min"), + tilewe.engine.RandomEngine("Random 1"), + tilewe.engine.RandomEngine("Random 2"), + tilewe.engine.RandomEngine("Random 3"), ]) - results = tournament.play(100, n_threads=multiprocessing.cpu_count(), move_seconds=1, elo_mode="estimated") + results = tournament.play(10, n_threads=2, move_seconds=1, elo_mode="estimated") + #results = tournament.play(100, n_threads=multiprocessing.cpu_count(), move_seconds=1, elo_mode="estimated") # print the result of game 1 - print(results.match_data[0].board) + #print(results.match_data[0].board) # print the total real time the tournament took and the average duration of each match, in seconds print(f"Tournament ran for {round(results.real_time, 4)}s with avg " + f"match duration {round(results.average_match_duration, 4)}s\n") # print the engine rankings sorted by win_counts desc and then by elo_error_margin asc - print(results.get_engine_rankings_display('win_counts', 'desc')) - print(results.get_engine_rankings_display('elo_error_margin', 'asc')) + #print(results.get_engine_rankings_display('win_counts', 'desc')) + #print(results.get_engine_rankings_display('elo_error_margin', 'asc')) if __name__ == '__main__': run_tournament() diff --git a/tilewe/engine.py b/tilewe/engine.py index a88c669..c98f3d3 100644 --- a/tilewe/engine.py +++ b/tilewe/engine.py @@ -86,11 +86,12 @@ class OpenCornersEngine(Engine): Fairly weak but does result in decent board coverage behavior. """ - def __init__(self, name: str="MostOpenCorners", style: str="max", estimated_elo: float=None): + def __init__(self, name: str=None, style: str="max", estimated_elo: float=None): if style not in ["max", "min"]: raise ValueError("Invalid style, must be 'max' or 'min'") - if estimated_elo is None: - estimated_elo = -250.0 if style == "min" else 15.0 + + name = name or ("MostOpenCorners" if style == "max" else "LeastOpenCorners") + estimated_elo = estimated_elo or (15.0 if style == "max" else -250.0) self.func = min if style == "min" else max super().__init__(name, estimated_elo) @@ -119,11 +120,12 @@ class PieceSizeEngine(Engine): ties, it's effectively a greedy form of RandomEngine. """ - def __init__(self, name: str="LargestPiece", style: str="max", estimated_elo: float=None): + def __init__(self, name: str=None, style: str="max", estimated_elo: float=None): if style not in ["max", "min"]: raise ValueError("Invalid style, must be 'max' or 'min'") - if estimated_elo is None: - estimated_elo = -150.0 if style == "min" else 30.0 + + name = name or ("LargestPiece" if style == "max" else "SmallestPiece") + estimated_elo = estimated_elo or (30.0 if style == "max" else -150.0) self.func = min if style == "min" else max super().__init__(name, estimated_elo) @@ -156,8 +158,9 @@ class MoveDifferenceEngine(Engine): def __init__(self, name: str="MaxMoveDiff", style: str="max", estimated_elo: float=None): if style not in ["max", "min"]: raise ValueError("Invalid style, must be 'max' or 'min'") - if estimated_elo is None: - estimated_elo = -200.0 if style == "min" else 50.0 + + name = name or ("MaxMoveDiff" if style == "max" else "MinMoveDiff") + estimated_elo = estimated_elo or (50.0 if style == "max" else -200.0) self.func = min if style == "min" else max super().__init__(name, estimated_elo) From 7e747b6ec09520a2e0dea8812b0541b85921eace Mon Sep 17 00:00:00 2001 From: Michael Conard Date: Mon, 27 Nov 2023 22:27:40 -0500 Subject: [PATCH 06/12] fix 0 vs None issue --- example_tournament.py | 9 ++++----- tilewe/__init__.py | 7 +++---- tilewe/engine.py | 6 +++--- 3 files changed, 10 insertions(+), 12 deletions(-) diff --git a/example_tournament.py b/example_tournament.py index 2d251b5..14ff1d4 100644 --- a/example_tournament.py +++ b/example_tournament.py @@ -19,19 +19,18 @@ def run_tournament(): tilewe.engine.RandomEngine("Random 3"), ]) - results = tournament.play(10, n_threads=2, move_seconds=1, elo_mode="estimated") - #results = tournament.play(100, n_threads=multiprocessing.cpu_count(), move_seconds=1, elo_mode="estimated") + results = tournament.play(100, n_threads=multiprocessing.cpu_count(), move_seconds=1, elo_mode="estimated") # print the result of game 1 - #print(results.match_data[0].board) + # print(results.match_data[0].board) # print the total real time the tournament took and the average duration of each match, in seconds print(f"Tournament ran for {round(results.real_time, 4)}s with avg " + f"match duration {round(results.average_match_duration, 4)}s\n") # print the engine rankings sorted by win_counts desc and then by elo_error_margin asc - #print(results.get_engine_rankings_display('win_counts', 'desc')) - #print(results.get_engine_rankings_display('elo_error_margin', 'asc')) + # print(results.get_engine_rankings_display('win_counts', 'desc')) + # print(results.get_engine_rankings_display('elo_error_margin', 'asc')) if __name__ == '__main__': run_tournament() diff --git a/tilewe/__init__.py b/tilewe/__init__.py index b2717e5..7a5f338 100644 --- a/tilewe/__init__.py +++ b/tilewe/__init__.py @@ -250,7 +250,6 @@ def is_legal(self, move: Move, for_player: Color=None) -> bool: from ctilewe import * # noqa: E402, F401, F403 -PIECE_TILES: list[int] = [n_piece_tiles(piece) for piece in range(NO_PIECE)] -PIECE_CORNERS: list[int] = [n_piece_corners(piece) for piece in range(NO_PIECE)] -PIECE_CONTACTS: list[int] = [n_piece_contacts(piece) for piece in range(NO_PIECE)] - +PIECE_TILES: list[int] = [n_piece_tiles(piece) for piece in range(NO_PIECE)] # noqa: E241, E272 +PIECE_CORNERS: list[int] = [n_piece_corners(piece) for piece in range(NO_PIECE)] # noqa: E241, E272 +PIECE_CONTACTS: list[int] = [n_piece_contacts(piece) for piece in range(NO_PIECE)] # noqa: E241, E272 diff --git a/tilewe/engine.py b/tilewe/engine.py index c98f3d3..b303c6c 100644 --- a/tilewe/engine.py +++ b/tilewe/engine.py @@ -91,7 +91,7 @@ def __init__(self, name: str=None, style: str="max", estimated_elo: float=None): raise ValueError("Invalid style, must be 'max' or 'min'") name = name or ("MostOpenCorners" if style == "max" else "LeastOpenCorners") - estimated_elo = estimated_elo or (15.0 if style == "max" else -250.0) + estimated_elo = (15.0 if style == "max" else -250.0) if estimated_elo is None else estimated_elo self.func = min if style == "min" else max super().__init__(name, estimated_elo) @@ -125,7 +125,7 @@ def __init__(self, name: str=None, style: str="max", estimated_elo: float=None): raise ValueError("Invalid style, must be 'max' or 'min'") name = name or ("LargestPiece" if style == "max" else "SmallestPiece") - estimated_elo = estimated_elo or (30.0 if style == "max" else -150.0) + estimated_elo = (30.0 if style == "max" else -150.0) if estimated_elo is None else estimated_elo self.func = min if style == "min" else max super().__init__(name, estimated_elo) @@ -160,7 +160,7 @@ def __init__(self, name: str="MaxMoveDiff", style: str="max", estimated_elo: flo raise ValueError("Invalid style, must be 'max' or 'min'") name = name or ("MaxMoveDiff" if style == "max" else "MinMoveDiff") - estimated_elo = estimated_elo or (50.0 if style == "max" else -200.0) + estimated_elo = (50.0 if style == "max" else -200.0) if estimated_elo is None else estimated_elo self.func = min if style == "min" else max super().__init__(name, estimated_elo) From 0b45f9b5e8eb4a59418314c88bfa290bda5e3550 Mon Sep 17 00:00:00 2001 From: Michael Conard Date: Mon, 27 Nov 2023 22:34:00 -0500 Subject: [PATCH 07/12] Missed one default param as None --- tilewe/engine.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tilewe/engine.py b/tilewe/engine.py index b303c6c..f7828e8 100644 --- a/tilewe/engine.py +++ b/tilewe/engine.py @@ -155,7 +155,7 @@ class MoveDifferenceEngine(Engine): getting access to an open area on the board, etc. """ - def __init__(self, name: str="MaxMoveDiff", style: str="max", estimated_elo: float=None): + def __init__(self, name: str=None, style: str="max", estimated_elo: float=None): if style not in ["max", "min"]: raise ValueError("Invalid style, must be 'max' or 'min'") From 470ab41a890c2ba1df79afdadd47d308fc5d5da8 Mon Sep 17 00:00:00 2001 From: Michael Conard Date: Mon, 27 Nov 2023 22:39:04 -0500 Subject: [PATCH 08/12] update name handling for tileweight too --- example_tournament.py | 8 +++----- tilewe/engine.py | 25 +++++++++++++++---------- 2 files changed, 18 insertions(+), 15 deletions(-) diff --git a/example_tournament.py b/example_tournament.py index 14ff1d4..cf3d2ed 100644 --- a/example_tournament.py +++ b/example_tournament.py @@ -10,13 +10,11 @@ def run_tournament(): tilewe.engine.MoveDifferenceEngine(style="min"), tilewe.engine.PieceSizeEngine(style="max"), tilewe.engine.PieceSizeEngine(style="min"), - tilewe.engine.TileWeightEngine("WallCrawler", 'wall_crawl'), - tilewe.engine.TileWeightEngine("Turtle", 'turtle'), + tilewe.engine.TileWeightEngine(style='wall_crawl'), + tilewe.engine.TileWeightEngine(style='turtle'), tilewe.engine.OpenCornersEngine(style="max"), tilewe.engine.OpenCornersEngine(style="min"), - tilewe.engine.RandomEngine("Random 1"), - tilewe.engine.RandomEngine("Random 2"), - tilewe.engine.RandomEngine("Random 3"), + tilewe.engine.RandomEngine(name="Random"), ]) results = tournament.play(100, n_threads=multiprocessing.cpu_count(), move_seconds=1, elo_mode="estimated") diff --git a/tilewe/engine.py b/tilewe/engine.py index f7828e8..27ee7f4 100644 --- a/tilewe/engine.py +++ b/tilewe/engine.py @@ -250,29 +250,34 @@ class TileWeightEngine(Engine): 'turtle': -40.0 } + names = { + 'wall_crawl': 'WallCrawler', + 'turtle': 'Turtle' + } + def __init__(self, - name: str="TileWeight", - weight_map: str='wall_crawl', + name: str=None, + style: str='wall_crawl', custom_weights: list[int | float]=None, estimated_elo: float=None): """ - Current `weight_map` built-in options are 'wall_crawl' and 'turtle' + Current `style` built-in options are 'wall_crawl' and 'turtle' Can optionally provide a custom set of weights instead """ - est_elo: float = 0.0 if estimated_elo is None else estimated_elo - if custom_weights is not None: if len(custom_weights) != 20 * 20: raise Exception("TileWeightEngine custom_weights must be a list of exactly 400 values") self.weights = custom_weights + name = name or "CustomTileWeights" + est_elo: float = 0.0 if estimated_elo is None else estimated_elo else: - if weight_map not in self.weight_maps: - raise Exception("TileWeightEngine given invalid weight_map choice") - self.weights = self.weight_maps[weight_map] - if estimated_elo is None: - est_elo = self.weight_elos[weight_map] + if style not in self.weight_maps: + raise Exception("TileWeightEngine given invalid style choice") + self.weights = self.weight_maps[style] + name = name or self.names[style] + est_elo: float = self.weight_elos[style] if estimated_elo is None else estimated_elo super().__init__(name, estimated_elo=est_elo) From 6229dde0e416032d169dac7a7165ad610bc32d18 Mon Sep 17 00:00:00 2001 From: Michael Conard Date: Mon, 27 Nov 2023 23:51:27 -0500 Subject: [PATCH 09/12] N_ prefix the tile data cache lists --- tilewe/__init__.py | 6 +++--- tilewe/engine.py | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/tilewe/__init__.py b/tilewe/__init__.py index e0d335c..a50d5c2 100644 --- a/tilewe/__init__.py +++ b/tilewe/__init__.py @@ -256,6 +256,6 @@ def is_legal(self, move: Move, for_player: Color=None) -> bool: from ctilewe import * # noqa: E402, F401, F403 -PIECE_TILES: list[int] = [n_piece_tiles(piece) for piece in range(NO_PIECE)] # noqa: E241, E272 -PIECE_CORNERS: list[int] = [n_piece_corners(piece) for piece in range(NO_PIECE)] # noqa: E241, E272 -PIECE_CONTACTS: list[int] = [n_piece_contacts(piece) for piece in range(NO_PIECE)] # noqa: E241, E272 +N_PIECE_TILES: list[int] = [n_piece_tiles(piece) for piece in range(NO_PIECE)] # noqa: E241, E272 +N_PIECE_CORNERS: list[int] = [n_piece_corners(piece) for piece in range(NO_PIECE)] # noqa: E241, E272 +N_PIECE_CONTACTS: list[int] = [n_piece_contacts(piece) for piece in range(NO_PIECE)] # noqa: E241, E272 diff --git a/tilewe/engine.py b/tilewe/engine.py index 44f7f1e..f8f41e9 100644 --- a/tilewe/engine.py +++ b/tilewe/engine.py @@ -136,9 +136,9 @@ def on_search(self, board: tilewe.Board, _seconds: float) -> tilewe.Move: def score(m: tilewe.Move): pc = m.piece - return (tilewe.PIECE_TILES[pc] * 100 + - tilewe.PIECE_CORNERS[pc] * 10 + - tilewe.PIECE_CONTACTS[pc]) + return (tilewe.N_PIECE_TILES[pc] * 100 + + tilewe.N_PIECE_CORNERS[pc] * 10 + + tilewe.N_PIECE_CONTACTS[pc]) best = self.func(moves, key=score) From c025d04d89413cb7d2c354008c314392309e80d1 Mon Sep 17 00:00:00 2001 From: Nicholas Hamilton Date: Mon, 27 Nov 2023 22:56:09 -0600 Subject: [PATCH 10/12] Use piece count value --- tilewe/__init__.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tilewe/__init__.py b/tilewe/__init__.py index a50d5c2..5de9b19 100644 --- a/tilewe/__init__.py +++ b/tilewe/__init__.py @@ -256,6 +256,6 @@ def is_legal(self, move: Move, for_player: Color=None) -> bool: from ctilewe import * # noqa: E402, F401, F403 -N_PIECE_TILES: list[int] = [n_piece_tiles(piece) for piece in range(NO_PIECE)] # noqa: E241, E272 -N_PIECE_CORNERS: list[int] = [n_piece_corners(piece) for piece in range(NO_PIECE)] # noqa: E241, E272 -N_PIECE_CONTACTS: list[int] = [n_piece_contacts(piece) for piece in range(NO_PIECE)] # noqa: E241, E272 +N_PIECE_TILES: list[int] = [n_piece_tiles(piece) for piece in range(PIECE_COUNT)] # noqa: E241, E272 +N_PIECE_CORNERS: list[int] = [n_piece_corners(piece) for piece in range(PIECE_COUNT)] # noqa: E241, E272 +N_PIECE_CONTACTS: list[int] = [n_piece_contacts(piece) for piece in range(PIECE_COUNT)] # noqa: E241, E272 From 83db5fb4ea7a71b39dc6cc5426e2b5d013730405 Mon Sep 17 00:00:00 2001 From: Michael Conard Date: Mon, 27 Nov 2023 23:59:24 -0500 Subject: [PATCH 11/12] allow >=3.10 not just ==3.10 --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index a64412c..3d348ff 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -7,7 +7,7 @@ authors = [ ] description = "A tile-placing game for AI development fun" readme = "README.md" -requires-python = "==3.10.*" +requires-python = ">=3.10.*" classifiers = [ "Programming Language :: Python :: 3", "License :: OSI Approved :: MIT License", From 1b4cbbaa73763973a2eecf057a65e372a71deadd Mon Sep 17 00:00:00 2001 From: Michael Conard Date: Tue, 28 Nov 2023 00:03:29 -0500 Subject: [PATCH 12/12] remove patch version --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 3d348ff..248674f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -7,7 +7,7 @@ authors = [ ] description = "A tile-placing game for AI development fun" readme = "README.md" -requires-python = ">=3.10.*" +requires-python = ">=3.10" classifiers = [ "Programming Language :: Python :: 3", "License :: OSI Approved :: MIT License",