Skip to content
Snippets Groups Projects
Commit 90c9b6b9 authored by Lukas Hoffleit's avatar Lukas Hoffleit
Browse files

Berechnung des besten Spielzugs

parent 309edd39
Branches
No related tags found
No related merge requests found
...@@ -3,8 +3,12 @@ import time ...@@ -3,8 +3,12 @@ import time
def main() -> None: def main() -> None:
ser = pc.connect() ser = pc.connect()
w = [130, 120, 18, 1, 1, 1, -1]; w = [130, 120, 18, 0, 0, -1];
pc.set_joint_angles(ser,1.07, 0.21, -0.15, -1.6, -1, 0, 2000) print(pc.move_pose(ser, w, 0, 2000));
print("moving to pose")
time.sleep(2000);
print("done")
#pc.set_joint_angles(ser,1.07, 0.21, -0.15, -1.6, -1, 0, 2000)
pc.sleep(ser) pc.sleep(ser)
pc.disconnect(ser) pc.disconnect(ser)
......
...@@ -5,6 +5,14 @@ class Player(Enum): ...@@ -5,6 +5,14 @@ class Player(Enum):
undefined = 0 undefined = 0
one = 1 one = 1
two = 2 two = 2
grid_full = 3
def get_opponent(player:Player) -> Player:
if player == Player.one:
return Player.two
else:
return Player.one
class TicTacToeError(Exception): class TicTacToeError(Exception):
"""TicTacToe Error""" """TicTacToe Error"""
...@@ -16,7 +24,11 @@ class TicTacToe(): ...@@ -16,7 +24,11 @@ class TicTacToe():
grid.append([Player.undefined, Player.undefined, Player.undefined]) grid.append([Player.undefined, Player.undefined, Player.undefined])
self.grid = np.array(grid) self.grid = np.array(grid)
def _get_player_from_int(self, player:Player|int) -> Player: @staticmethod
def _get_player_from_int(player:Player|int) -> Player:
"""
Internal helper methot to return a Player-Object from Int or Player
"""
if isinstance(player, int): if isinstance(player, int):
try: try:
return Player(player) return Player(player)
...@@ -24,45 +36,57 @@ class TicTacToe(): ...@@ -24,45 +36,57 @@ class TicTacToe():
raise TicTacToeError("The player number is invalid. Only '1' and '2' are accepted") raise TicTacToeError("The player number is invalid. Only '1' and '2' are accepted")
return player return player
def add(self, row:int, col:int, player:Player|int) -> bool: def add(self, row:int, col:int, player:Player|int, grid:np.ndarray|None = None) -> bool:
""" Change the value of a undefined field. """ Change the value of a undefined field.
The player can be passed as Player Object or plain Int. The player can be passed as Player Object or plain Int.
Returns True, if executed correctly. Returns True, if executed correctly.
Returns False, if the field is already occupied Returns False, if the field is already occupied
or the player number is invalid. or the player number is invalid.
""" """
if grid is None:
grid = self.grid
player = self._get_player_from_int(player) player = self._get_player_from_int(player)
if self.check_field(row, col): if self.check_field(row, col, grid):
self.grid[row][col] = player grid[row][col] = player
return True return True
return False return False
def check_field(self, row:int, col:int) -> bool: def check_field(self, row:int, col:int, grid:np.ndarray|None = None) -> bool:
"""Checks, if a field is occupied""" """Checks, if a field is occupied"""
if grid is None:
grid = self.grid
if self.grid[row][col] != Player.undefined: if self.grid[row][col] != Player.undefined:
return False return False
return True return True
def print_grid(self) -> None: def print_grid(self, grid:np.ndarray|None=None) -> None:
"""
Prints the current state of a grid.
If no grid is specified, the current game grid (self.grid) is printed
"""
if grid is None:
grid = self.grid
symbols = { symbols = {
Player.one: "X", Player.one: "X",
Player.two: "O", Player.two: "O",
Player.undefined: " " Player.undefined: " "
} }
print("┌───┬───┬───┐") print("\t┌───┬───┬───┐")
for i, row in enumerate(self.grid): for i, row in enumerate(grid):
print("", end="") print("\t", end="")
for field in row: for field in row:
print(f" {symbols[field]}", end="") print(f" {symbols[field]}", end="")
if i < len(self.grid) - 1: if i < len(grid) - 1:
print("\n├───┼───┼───┤") print("\n\t├───┼───┼───┤")
print("\n└───┴───┴───┘\n\n") print("\n\t└───┴───┴───┘\n\n")
def check_winner(self, grid:np.ndarray|None = None) -> Player: def check_winner(self, grid:np.ndarray|None = None) -> Player:
""" Checks, if the game is won. """
Checks, if the game is won.
If the game is won by a player, returns this player. If the game is won by a player, returns this player.
Else, returns Player.undefined """ Else, returns Player.undefined
"""
if grid is None: if grid is None:
grid = self.grid grid = self.grid
...@@ -83,21 +107,90 @@ class TicTacToe(): ...@@ -83,21 +107,90 @@ class TicTacToe():
if grid[1, 1] != Player.undefined: if grid[1, 1] != Player.undefined:
return grid[1, 1] return grid[1, 1]
# Base Case - No winner # No winner
if Player.undefined in grid:
return Player.undefined return Player.undefined
return Player.grid_full
def is_won(self, player:Player|int) -> bool: def _maximize(self, grid:np.ndarray) -> float:
player = self._get_player_from_int(player) """
return self.check_winner() == player Helper Method for the maximizing Player
"""
best = -np.inf
for i in range(3):
for j in range(3):
if grid[i, j] == Player.undefined:
grid[i, j] = self.active_player
score = self._evaluate_recursively(grid, self.opponent)
grid[i, j] = Player.undefined
best = max(best, score)
return best
def _minimize(self, grid:np.ndarray) -> float:
"""
Helper Method for the minimizing player
"""
best = np.inf
for i in range(3):
for j in range(3):
if grid[i, j] == Player.undefined:
grid[i, j] = self.opponent
score = self._evaluate_recursively(grid, self.active_player)
grid[i, j] = Player.undefined
best = min(best, score)
return best
def _evaluate_recursively(self, grid:np.ndarray, current:Player) -> float:
"""
Helper Method for calculating the best move.
Recursively evaluate the board state from the perspective of `current`.
"""
winner = self.check_winner(grid)
if winner == self.active_player:
return 1
elif winner == get_opponent(self.active_player):
return -1
# Draw
if not any(cell == Player.undefined for row in grid for cell in row):
return 0
if current == self.active_player:
return self._maximize(grid)
else:
return self._minimize(grid)
def get_best_move(self, player:Player|int) -> tuple[int, int]:
"""
Returns the best move for the given Player as a tuple of integers.
"""
self.active_player = self._get_player_from_int(player)
self.opponent = get_opponent(self.active_player)
best_score = -np.inf
move = (-1, -1)
for i in range(3):
for j in range(3):
if self.grid[i, j] == Player.undefined:
self.grid[i, j] = self.active_player
score = self._evaluate_recursively(self.grid, self.opponent)
self.grid[i, j] = Player.undefined
if score > best_score:
best_score = score
move = (i, j)
return move
if __name__ == "__main__": if __name__ == "__main__":
ttt = TicTacToe() ttt = TicTacToe()
ttt.add(1, 1, 1) #ttt.add(1, 1, 1)
ttt.print_grid() #ttt.print_grid()
ttt.add(0, 1, 2) #ttt.add(2, 1, 2)
ttt.print_grid() ttt.print_grid()
ttt.add(0, 0, 1) current_player = Player.one
ttt.print_grid() while ttt.check_winner() == Player.undefined:
ttt.add(0, 2, 2) move = ttt.get_best_move(current_player)
ttt.add(move[0], move[1], current_player)
if current_player == Player.one:
current_player = Player.two
else:
current_player = Player.one
ttt.print_grid() ttt.print_grid()
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment