aboutsummaryrefslogtreecommitdiff
path: root/src/ghost.py
blob: 301645bb04ee7a20e35087841711ab60c8266677 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
import pygame
import math
from util import get_sprites
from settings import settings
import map as Map

dx = [1, 0, -1, 0]  # right, down, left, up
dy = [0, 1, 0, -1]

inv_dir = [2, 3, 0, 1]
sprite_sheet = [2, 0, 3, 1]


class Ghost():
    def __init__(self, sprite_sheet, color, x, y):
        self.x = x
        self.y = y
        self.sprite = get_sprites(sprite_sheet)
        self.color = color
        self.last_move = 3  # this represents the direction based on the dx, dy arrays
        self.speed = 3

    def in_bounds(self, pos):
        (x, y) = pos
        return (x >= 0) and (y >= 0) and (x < settings.width - 30) and (y < settings.height)

    def heuristic(self, next_pos, tx, ty):
        return abs(next_pos[0] - tx) + abs(next_pos[1] - ty)

    # checks if the current position of pacman is either a dot, big dot or free

    def is_valid(self, maze, x, y):
        if x >= 0 and x < 30:  # Necessary to make portals work
            is_dot = maze[y][x] == Map.D
            is_big_dot = maze[y][x] == Map.BD
            is_free = maze[y][x] == 0
            return (is_dot or is_free or is_big_dot)
        return True

    # checks collision with pacman and obstacles returns false if there is a collision and true otherwise
    def check_collision(self, nx, ny, gx, gy, maze):
        direct_x = [1, 0, -1, 0, 1, 1, -1, -1]
        direct_y = [0, 1, 0, -1, -1, 1, -1, 1]

        for i in range(len(direct_x)):
            px = nx + direct_x[i] * 14
            py = ny + direct_y[i] * 14
            x = px // gx
            y = py // gy
            if not self.is_valid(maze, x, y):
                return False

        return True

    def get_next_move(self, pacman, maze, screen, blinky):

        ret = len(dx) * [math.inf]

        forbidden = inv_dir[self.last_move]

        for i in range(len(dx)):
            nx = self.x + dx[i] * self.speed
            ny = self.y + dy[i] * self.speed
            if self.check_collision(nx, ny, 30, 30, maze):
                if i != forbidden:
                    ret[i] = self.heuristic((nx, ny), pacman.x, pacman.y)
                    if settings.debug:
                        pygame.draw.line(screen, self.color, (pacman.x, pacman.y),
                                         (self.x, self.y), 1)

        min_h = min(ret)

        # Favour going up when there is a conflict
        if min_h == ret[3] and min_h != math.inf:
            return 3
        min_idx = ret.index(min_h)
        return min_idx

    def move(self, maze, pacman, screen, game_over, blinky):
        if abs(pacman.x - self.x) <= 15 and abs(pacman.y - self.y) <= 15:
            game_over[0] = True
        min_idx = self.get_next_move(pacman, maze, screen, blinky)
        new_dx = dx[min_idx] * self.speed
        new_dy = dy[min_idx] * self.speed
        self.x += new_dx
        self.y += new_dy
        self.x %= 900  # The logic of the portal
        self.last_move = min_idx

    def draw(self, screen):
        radius = 30 // 2
        pos = (self.x - radius, self.y - radius)
        image = pygame.transform.scale(
            self.sprite[sprite_sheet[self.last_move]], (40, 40))
        screen.blit(image, pos)