Untitled

mail@pastecode.io avatar
unknown
python
7 months ago
12 kB
3
Indexable
Never
import numpy as np
import pygame 
import math

class IsolationGame: 
    def __init__(self):
        self.board = np.array([[' ' for _ in range(6)] for _ in range(6)])
        self.board[0, 0] = '1'  # speler 1 startpositie
        self.board[5, 5] = '2'  # speler 2 startpositie
        self.player = 1
        self.player_positions = [(0, 0), (5, 5)]  # houdt de posities van de spelers bij 
        self.game_over = False
    
    def __str__(self):
        board_str = '\n'.join([' '.join(row) for row in self.board])
        return board_str
    
    def is_move_valid(self, x, y, new_x, new_y):
        if not (0 <= new_x < 6 and 0 <= new_y < 6):
            return False
        if self.board[new_x, new_y] != ' ':
            return False
        
        # controleert of de zet geldig is (voor een koningin)
        dx = new_x - x
        dy = new_y - y
        if dx != 0 and dy != 0 and abs(dx) != abs(dy):
            return False
        if dx == 0 and dy == 0:
            return False
        
        # controleert voor blokkades
        step_x = 1 if dx > 0 else -1 if dx < 0 else 0
        step_y = 1 if dy > 0 else -1 if dy < 0 else 0
        steps = max(abs(dx), abs(dy))
        for step in range(1, steps):
            if self.board[x + step * step_x, y + step * step_y] != ' ':
                return False
        return True

    def move(self, new_x, new_y):
        if self.game_over:
            print("Game is already over.")
            return False
        
        current_position = self.player_positions[self.player - 1]
        if self.is_move_valid(*current_position, new_x, new_y):
            self.board[current_position] = 'X'  # markeer het oude vak als geblokkeerd
            self.board[new_x, new_y] = str(self.player)
            self.player_positions[self.player - 1] = (new_x, new_y)  # update de positie
            
            self.player = 1 if self.player == 2 else 2  # wissel van speler
            
            # controleer na de zet of de volgende speler geen geldige zetten meer heeft
            if self.terminal_state(self.player_positions[self.player - 1]):
                print(f"Game over. Player {3 - self.player} wins!")
                self.game_over = True
            return True 
        else: 
            print("Invalid move") 
        return False

    def terminal_state(self, player_position):
        directions = [(1, 0), (-1, 0), (0, 1), (0, -1), (1, 1), (-1, -1), (1, -1), (-1, 1)]
        x, y = player_position
        for dx, dy in directions:
            new_x, new_y = x + dx, y + dy
            # controleer of de nieuwe positie binnen het bord is en of het veld leeg is.
            if 0 <= new_x < 6 and 0 <= new_y < 6 and self.board[new_x, new_y] == ' ':
                return False  # er is een geldige zet gevonden
        return True  # geen geldige zetten gevonden, spel is voorbij

class IsolationGameAI(IsolationGame): # klasse met alle AI gebeuren
    def __init__(self):
        super().__init__() # roept de constructor van de parent klasse aan (IsolationGame)
        self.max_depth = 4  # depth. bij 4 gaat het lang duren (zelfs op mijn pc die eigenlijk best goed is) en lager dan 2 dan is hij dom. met AB pruning wordt sneller miss
        

    def move(self, new_x, new_y): # als speler 2 is, dan speelt AI
        if self.player != 2: 
            return super().move(new_x, new_y)

        best_score = -math.inf 
        best_move = None 
        current_position = self.player_positions[self.player - 1]
        # reset max_distance voor elke nieuwe zet beslissing
        self.max_distance = -math.inf

        for x in range(6): # simuleert elke mogelijke zet, roept minimax aan om score te berekenen en houdt het bij
            for y in range(6):
                if self.is_move_valid(*current_position, x, y):
                    self.board[current_position] = 'X'
                    self.board[x, y] = '2'
                    self.player_positions[self.player - 1] = (x, y)
                    score = self.alpha_beta_pruning(0, -math.inf, math.inf, True)
                    self.board[x, y] = ' '
                    self.board[current_position] = '2'
                    self.player_positions[self.player - 1] = current_position

                    # update de beste score EN zet gebaseerd op de geëvalueerde afstand
                    if score > best_score:
                        best_score = score
                        best_move = (x, y)

        if best_move is None:
            print("No valid moves available. Player 1 wins!")
            self.game_over = True
            return False

        return super().move(*best_move) # roept de move functie van de parent klasse aan


        

    def alpha_beta_pruning(self, depth, alpha, beta, is_maximizing):
        if depth == self.max_depth or self.terminal_state(self.player_positions[self.player - 1]):
            return self.heuristiek_1() # returnt de score van de huidige positie 

        original_board = self.board.copy() # kopie van het bord
        original_positions = self.player_positions.copy() # kopie van de posities van de spelers 

        if is_maximizing: 
            max_eval = -math.inf 
            for x in range(6): 
                for y in range(6):
                    if self.is_move_valid(*self.player_positions[self.player - 1], x, y):
                        self.board[self.player_positions[self.player - 1]] = 'X'
                        self.board[x, y] = '2'
                        self.player_positions[self.player - 1] = (x, y)
                        eval = self.alpha_beta_pruning(depth + 1, alpha, beta, False)
                        self.board = original_board.copy()
                        self.player_positions = original_positions.copy()
                        max_eval = max(max_eval, eval)
                        alpha = max(alpha, eval)
                        if beta <= alpha:
                            break
                if beta <= alpha:
                    break
            return max_eval
        else:
            min_eval = math.inf
            for x in range(6):
                for y in range(6):
                    if self.is_move_valid(*self.player_positions[1 - self.player], x, y):
                        self.board[self.player_positions[1 - self.player]] = 'X'
                        self.board[x, y] = '1'
                        self.player_positions[1 - self.player] = (x, y)
                        eval = self.alpha_beta_pruning(depth + 1, alpha, beta, True)
                        self.board = original_board.copy()
                        self.player_positions = original_positions.copy()
                        min_eval = min(min_eval, eval)
                        beta = min(beta, eval)
                        if beta <= alpha:
                            break
                if beta <= alpha:
                    break
            return min_eval


    # heuristiek - hoe minder zetten mijn tegenstander heeft, hoe groter mijn voordeel
    def heuristiek_1(self): #positief is goed voor speler 2 (AI), negatief is goed voor speler 1 (mens). denk aan schaken
        player_1_moves = self.get_available_moves(self.player_positions[0])
        player_2_moves = self.get_available_moves(self.player_positions[1])
        return len(player_2_moves) - len(player_1_moves) # init bladwaarden (bv 6-4= +2)
    
    def heuristiek_2(self):
        opponent_position = self.player_positions[0]
        player_2_moves = self.get_available_moves(self.player_positions[1])
        max_distance = -1 

        for move in player_2_moves:
            dx = move[0] - opponent_position[0]
            dy = move[1] - opponent_position[1]
            distance = (dx ** 2 + dy ** 2) ** 0.5  # euclidische afstand
            if distance > max_distance:
                max_distance = distance

        return max_distance


    def get_available_moves(self, player_position):
        moves = []
        x, y = player_position
        directions = [(1, 0), (-1, 0), (0, 1), (0, -1), (1, 1), (-1, -1), (1, -1), (-1, 1)]
        for dx, dy in directions:
            new_x, new_y = x + dx, y + dy
            if 0 <= new_x < 6 and 0 <= new_y < 6 and self.board[new_x, new_y] == ' ':
                moves.append((new_x, new_y))
        return moves

class IsolationGamePygame: 
    def __init__(self): 
        pygame.init() 
        self.font = pygame.font.SysFont("arial", 36)
        self.screen = pygame.display.set_mode((600, 600))
        self.clock = pygame.time.Clock()
        self.game = IsolationGameAI()
        self.cell_size = 100
        self.running = True

        self.black_queen = pygame.image.load("img\\black_queen.png")
        self.white_queen = pygame.image.load("img\\white_queen.png")

    def draw_board(self):
        queen_size = int(self.cell_size * 0.6)  # 
        for x in range(6):
            for y in range(6):
                rect = pygame.Rect(x * self.cell_size, y * self.cell_size, self.cell_size, self.cell_size)
                pygame.draw.rect(self.screen, pygame.Color('grey' if (x + y) % 2 == 0 else 'white'), rect)
                if self.game.board[y, x] == '1':
                    queen_rect = self.white_queen.get_rect(center=rect.center)
                    queen_rect.width = queen_size
                    queen_rect.height = queen_size
                    self.screen.blit(pygame.transform.scale(self.white_queen, (queen_size, queen_size)), queen_rect)
                elif self.game.board[y, x] == '2':
                    queen_rect = self.black_queen.get_rect(center=rect.center)
                    queen_rect.width = queen_size
                    queen_rect.height = queen_size
                    self.screen.blit(pygame.transform.scale(self.black_queen, (queen_size, queen_size)), queen_rect)
                elif self.game.board[y, x] == 'X':
                    pygame.draw.line(self.screen, pygame.Color('blue'), rect.topleft, rect.bottomright, 5)
                    pygame.draw.line(self.screen, pygame.Color('blue'), rect.bottomleft, rect.topright, 5)

    def run(self):
        while self.running:
            for event in pygame.event.get():
                if self.game.game_over:
                    self.show_game_over_message(3 - self.game.player) # toon bericht met de winnaar
                    pygame.time.wait(5000) # wacht 5 seconden
                    self.running = False # stop de game loop

                if event.type == pygame.QUIT:
                    self.running = False
                elif event.type == pygame.MOUSEBUTTONDOWN:
                    # bepaal de cel waarin geklikt is
                    x, y = event.pos
                    grid_y, grid_x = x // self.cell_size, y // self.cell_size # Draai x en y om
                    
                    if self.game.player == 1:  # splr 1 is menselijke speler
                        if self.game.is_move_valid(*self.game.player_positions[self.game.player - 1], grid_x, grid_y):
                            self.game.move(grid_x, grid_y)
                            if not self.game.game_over:
                                self.ai_move()  # call de zet van de AI na de zet van de speler
                        else:
                            print("Invalid move")
                    

            self.screen.fill(pygame.Color('black'))
            self.draw_board()
            pygame.display.flip()
            self.clock.tick(60)

        pygame.quit()

    def ai_move(self):
        self.game.move(None, None)  # AI doet een zet
        self.draw_board()  # update het bord

    def show_game_over_message(self, winner):
        message = f"Game Over. Player {winner} wins!"
        text_surface = self.font.render(message, True, pygame.Color('orange'))
        text_rect = text_surface.get_rect(center=(300, 300))  # centreer het bericht
        self.screen.blit(text_surface, text_rect)
        pygame.display.flip()  # update het scherm om het bericht te tonen

if __name__ == "__main__":
    game_vis = IsolationGamePygame()
    game_vis.run() 
Leave a Comment