From 6190790a283f1e06ba47ba292621fa5239cc985c Mon Sep 17 00:00:00 2001 From: DylanVsn <43576618+DylanVsn@users.noreply.github.com> Date: Sun, 17 Nov 2019 18:51:03 +0100 Subject: [PATCH] ajout du dossier livrable avec readme.txt et code fonctionnel --- livrables/1/README.txt | 0 livrables/1/graphic.py | 67 +++++++++ livrables/1/pacman.py | 135 +++++++++++++++++ livrables/1/pacman_sprite.py | 13 ++ livrables/1/pacmap.py | 242 +++++++++++++++++++++++++++++++ livrables/1/pacmap_maze1.png | Bin 0 -> 12025 bytes livrables/1/pacmap_rule.txt | 9 ++ livrables/1/physic_engine.py | 21 +++ livrables/1/test_connexity.py | 45 ++++++ livrables/1/test_load_picture.py | 13 ++ 10 files changed, 545 insertions(+) create mode 100644 livrables/1/README.txt create mode 100755 livrables/1/graphic.py create mode 100755 livrables/1/pacman.py create mode 100755 livrables/1/pacman_sprite.py create mode 100755 livrables/1/pacmap.py create mode 100644 livrables/1/pacmap_maze1.png create mode 100644 livrables/1/pacmap_rule.txt create mode 100755 livrables/1/physic_engine.py create mode 100755 livrables/1/test_connexity.py create mode 100755 livrables/1/test_load_picture.py diff --git a/livrables/1/README.txt b/livrables/1/README.txt new file mode 100644 index 0000000..e69de29 diff --git a/livrables/1/graphic.py b/livrables/1/graphic.py new file mode 100755 index 0000000..02d5521 --- /dev/null +++ b/livrables/1/graphic.py @@ -0,0 +1,67 @@ +#!/usr/bin/env python3 + +import pygame as pg +import pacman_sprite +import pacman as m_pacman # m_ for module to avoid conflicts +from physic_engine import PhysicEngine +import pacmap as m_pacmap +import sys + +pg.init() + +class Screen: + def __init__(self, size, pacmap: m_pacmap.Map, physic_engine: PhysicEngine, pacman: m_pacman.Pacman): + self.screen = pg.display.set_mode(size) + # self.screen.set_caption("Pacman") + self.physic_engine = physic_engine + self.pacman = pacman + self.pacman_sprite = pacman_sprite.PacmanSprite(size[0]/28) + self.clock = pg.time.Clock() + self.max_fps = 40 + self.entity_group = pg.sprite.Group(self.pacman_sprite) + self.loop() + + + def user_events(self): + key = pg.key.get_pressed() + if key[pg.K_UP]: + pacman.set_next_dir(m_pacman.direction.up) + if key[pg.K_DOWN]: + pacman.set_next_dir(m_pacman.direction.down) + if key[pg.K_LEFT]: + pacman.set_next_dir(m_pacman.direction.left) + if key[pg.K_RIGHT]: + pacman.set_next_dir(m_pacman.direction.right) + + def refresh(self): + """refresh/redraw all""" + pac_x, pac_y = self.pacman.position + pac_res = self.pacman.resolution + pacmap.draw(self.screen) + self.pacman_sprite.rect.x = int(pac_x / 28 / pac_res * self.screen.get_width()) - 10 + self.pacman_sprite.rect.y = int(pac_y / 31 / pac_res * self.screen.get_height()) - 10 + self.entity_group.draw(self.screen) + + + def create_maze_surface(self): + pass + + def loop(self): + while 1: + self.screen.fill((0, 0, 0)) + for event in pg.event.get(): + if event.type == pg.QUIT: + sys.exit() + + self.user_events() + self.physic_engine.move_all() + self.refresh() + + self.clock.tick(self.max_fps) + pg.display.flip() + +if __name__ == '__main__': + pacman = m_pacman.Pacman((1,1)) + pacmap = m_pacmap.Map(maze_img_file="pacmap_maze1.png") + phys_engine = PhysicEngine(pacmap, pacman) + screen = Screen((560, 620), pacmap, phys_engine, pacman) diff --git a/livrables/1/pacman.py b/livrables/1/pacman.py new file mode 100755 index 0000000..867a261 --- /dev/null +++ b/livrables/1/pacman.py @@ -0,0 +1,135 @@ +import pacmap +import os + +from enum import IntEnum +from collections import namedtuple + +_tempdir = namedtuple("Direction", ["up", "down", "left", "right", "none"]) +direction = _tempdir( + up= (0, -1), + down=(0, 1), + left=(-1, 0), + right=(1, 0), + none=(0, 0) +) +pacdot_counter = 88 +score = 0 +lives = 3 + +class FruitType(IntEnum): + A = 0 + +class Fruit: + def __init__(self, fruit_type, score, position = (0, 0)): + self.fruit_type = fruit_type + self.score = score + self.position = position + + +class Pacman: + def __init__(self, position=[0, 0], map_size=(28, 31), resolution=10): + self.position = [position[0]*resolution+int(resolution/2), position[1]*resolution+int(resolution/2)] + self.direction = direction.right + self.next_direction = direction.none + self.super_power = 0 # Counter of super pacdots in effect (> 0 means super power is active) + self.ghost_combo = 0 + self.size = (1.8, 1.8) # size related to tile size + self.speed = 0.1 + self.resolution = resolution # when pacman in 0:10 he's in the 1st cell if resolution=10 !!! must be even number + self.map_size = map_size + + def matrix_position(self): + return int(self.position[0] / self.resolution), int(self.position[1] / self.resolution) + + def next_matrix_position(self): + next_x = int(self.position[0] / self.resolution + self.direction[0]) % self.map_size[0] + next_y = int(self.position[1] / self.resolution + self.direction[1]) % self.map_size[1] + return next_x, next_y + + def has_super_power(self): + return self.super_power > 0 + + def eat_pacdot(self, dot_map): + global score + global pacdot_counter + dot_map.dots_map[self.matrix_position()[0]][self.matrix_position()[1]] = pacmap.DotTile.NDT + pacdot_counter -= 1 + score += 10 + if pacdot_counter == 0: + game_over("win") + + def eat_super_pacdot(self, dot_map): + global score + dot_map.dots_map[self.matrix_position()[0]][self.matrix_position()[1]] = pacmap.DotTile.NDT + score += 50 + self.super_power += 1 + + # TODO + # Requires UNIX - or use of async + # pid = os.fork() + #if pid == 0: + # return + + #os.sleep(10) + self.super_power -= 1 + self.ghost_combo = 0 + + def eat_fruit(self, fruit, dot_map): + global score + dot_map.dots_map[self.matrix_position()[0]][self.matrix_position()[1]] = pacmap.DotTile.NDT + score += fruit.score + + def eat_ghost(self, ghost): + global score + ghost.despawn_and_respawn() + self.ghost_combo += 1 + score += (2 ** self.ghost_combo) * 100 + + def get_eaten(self, dot_map): + global lives + #TODO score loss ? + self.position = dot_map.spawn_point #TODO + lives -= 1 + if lives < 0: # à vérifier + game_over() + + def is_at_center_tile(self): + """return True if pacman is at the center of a tile else False""" + clause_1 = not self.position[0] % (self.resolution/2) and self.position[0] % self.resolution + clause_2 = not self.position[1] % (self.resolution/2) and self.position[1] % self.resolution + return clause_1 and clause_2 + + def change_dir(self, new_dir): + self.direction = new_dir + + def set_next_dir(self, next_dir): + if next_dir[0] and self.direction[0]: + self.change_dir(next_dir) + elif next_dir[1] and self.direction[1]: + self.change_dir(next_dir) + else: + self.next_direction = next_dir + + def change_to_next_dir(self): + self.direction = self.next_direction + self.next_direction = direction.none + + def get_next_dir_tile(self): + """return x, y corresponding to the tile if we move with next_direction""" + next_x = int(self.position[0] / self.resolution + self.next_direction[0]) % self.map_size[0] + next_y = int(self.position[1] / self.resolution + self.next_direction[1]) % self.map_size[1] + return next_x, next_y + + def move(self): + self.position[0] = (self.position[0] + self.direction[0]) % (self.resolution * self.map_size[0]) + self.position[1] = (self.position[1] + self.direction[1]) % (self.resolution * self.map_size[1]) + +def game_over(status = "lose"): + #TODO + pass + + + + + + diff --git a/livrables/1/pacman_sprite.py b/livrables/1/pacman_sprite.py new file mode 100755 index 0000000..4ecfe76 --- /dev/null +++ b/livrables/1/pacman_sprite.py @@ -0,0 +1,13 @@ +"""Pacman Graphic Object""" +import pygame as pg + +class PacmanSprite(pg.sprite.Sprite): + def __init__(self, size): + super().__init__() + self.image = pg.Surface([size, size]) + half_size = int(size / 2) + pg.draw.circle(self.image, (255, 255, 0), (half_size, half_size), half_size) + + # Fetch the rectangle object that has the dimensions of the image + # Update the position of this object by setting the values of rect.x and rect.y + self.rect = self.image.get_rect() \ No newline at end of file diff --git a/livrables/1/pacmap.py b/livrables/1/pacmap.py new file mode 100755 index 0000000..7cb35d1 --- /dev/null +++ b/livrables/1/pacmap.py @@ -0,0 +1,242 @@ +from enum import IntEnum +from copy import deepcopy +from PIL import Image +import pygame +import os + +class DotTile(IntEnum): + NDT = 0 # no dot + SPD = 1 # small pac-dot + BPD = 2 # big pac-dot + FRT = 3 # fruit + +class PhysTile(IntEnum): + GRD = 0 # ground + WAL = 1 # wall + GSD = 2 # ghost door + GWL = 3 # ghost cell wall + GCF = 4 # ghost cell floor + TPT = 5 # teleporter tile + FIT = 6 # fully inaccessible tile + # ghost-cell ground as FIT ? verify no pac-dot here + +class CrossTile(IntEnum): + # code where we can find another GRD/TPT Tile from a given Tile + # with binary masks + UP = 1 # 0001 + DOWN = 2 # 0010 + LEFT = 4 # 0100 + RIGHT = 8 # 1000 + # direction changement if != 3 or != 12 + +class Map: + """ + Pacman maps size is 28×31 + """ + + width = 28 + height = 31 + # tile_size = 16 # tile subdivision for dynamic movement + + def __init__(self, phys_map = [], dots_map = [], maze_img_file=""): + """ + physic_map is the array containing elements: + 0: ground tile + 1: wall + 2: ghost door + 3: teleporter (no need to precise which to go because we assume it will + be at the opposite map tile) + 4: fully inaccessible tile (basically tiles that represent the "in-wall" + space) + + dots_map is a layer on top of the physic_map of the same dimension which contains + 0: no dot + 1: small pac-dot + 2: big pac-dot + """ + self._surf = pygame.Surface((Map.width * 20, Map.height * 20)) + if maze_img_file and os.path.isfile(maze_img_file): + try: + self.phys_map = self.decode_map(maze_img_file) + except Exception as e: + raise e + else: + self.phys_map = phys_map # in the first part we assume phys_map is correct and no need to verify + self.dots_map = dots_map + self.intersect_map = [] # TODO - the layer which contains intersections pre-calculated + + + def verify(self, phys_map, dots_map) -> bool: + """ + This method will verify if a given map is valid or not + Return True if correct else False + + we will assume + there are only: + - 1 ghost door + - 4 big pac-dots + - 240 pac-dots + + Each ground tile must have at least 2 ground tile neighboors because + there is no dead-end tile in pac-man + Each dot must be on a ground tile (not even a teleporter one) + """ + + if not (len(phys_map) == len(dots_map) == 31): + return False + + for i in range(len(phys_map)): + if not (len(phys_map[i]) == len(dots_map[i]) == 28): + return False + + # 1 ghost door verification + if sum(sub_arr.count(PhysTile.GSD) for sub_arr in phys_map) != 1: + return False + + # # 4 big pac dots + if sum(sub_arr.count(DotTile.BPD) for sub_arr in dots_map) != 4: + return False + + # # 240 small pac-dots + if sum(sub_arr.count(DotTile.SPD) for sub_arr in dots_map) != 240: + return False + + # dots are only in ground tile + for row in range(len(phys_map)): + for col in range(len(phys_map[0])): + if dots_map[row][col] and phys_map[row][col]: # no dot = 0; ground = 0 + return False + + # odd number of teleporter tiles + teleporter_count = sum(sub_arr.count(PhysTile.TPT) for sub_arr in phys_map) + if teleporter_count % 2: + return False + + edges = phys_map[0][1:] + phys_map[-1][1:] + [sub[0] for sub in phys_map] \ + + [sub[-1] for sub in phys_map][1:-1] + + # no ground tile on edges + if PhysTile.GRD in edges: + return False + + # teleporters are in front of the other + for col in range(1, len(phys_map[0])-1): + if phys_map[0][col] == PhysTile.TPT or phys_map[-1][col] == PhysTile.TPT: + if phys_map[0][col] == phys_map[-1][col]: + teleporter_count -= 2 + else: + return False + for row in range(1, len(phys_map)-1): + if phys_map[row][0] == PhysTile.TPT or phys_map[row][-1] == PhysTile.TPT: + if phys_map[row][0] == phys_map[row][-1]: + teleporter_count -= 2 + else: + return False + + if teleporter_count: # not all teleporters are on edges + return False + + # no teleporter on corners + if any(PhysTile.TPT in (phys_map[0][0], phys_map[0][-1], + phys_map[self.height-1][0], phys_map[-1][-1])): + return False + + # now we have to verify there is no dead-end ground tile + for col in range(1, self.width-1): + for row in range(1, self.height-1): + cpt = 0 + for x, y in ((0, 1), (1, 0), (-1, 0), (0, -1)): + if phys_map[row+y][col+x] in (PhysTile.GRD, PhysTile.TPT): + cpt += 1 + if cpt == 2: + break + if cpt < 2: + return False + # we have to verify if there is only 1 connexity component of (PhysTile.GRD, PhysTile.TPT, PhysTile.BPD, PhysTile.SPD) + if not connex(phys_map): + return False + + return True + + def get_tile(self, x, y): + return self.phys_map[y][x] + + def create_cross_layer(self): + dictionnary = { + (0, 1):CrossTile.DOWN, + (0, -1): CrossTile.UP, + (1, 0): CrossTile.RIGHT, + (-1, 0): CrossTile.LEFT + } + for row in range(self.height): + self.intersect_map.append([]) + for col in range(self.width): + if not self.get_tile(col, row) in (PhysTile.GRD, PhysTile.TPT): + self.intersect_map[-1].append(0) + if self.get_tile(col, row) in (PhysTile.GRD, PhysTile.TPT): + cpt = 0 + for dir in dictionnary: + test_col = (col + dir[0]) % self.width + test_row = (row + dir[1]) % self.height + if self.get_tile(test_col, test_row) in (PhysTile.GRD, PhysTile.TPT): + cpt |= dictionnary[dir] + self.intersect_map[-1].append(cpt) + + def draw(self, surf): + surf.blit(self._surf, (0, 0)) + + def decode_map(self, img_file): + img = Image.open(img_file) + dictionnary = { + (0 , 0, 0): PhysTile.GRD, + (255, 0, 255): PhysTile.GCF, + (0 , 0, 255): PhysTile.WAL, + (0 , 255, 0): PhysTile.GSD, + (0 , 255, 255): PhysTile.GWL, + (255, 0, 0): PhysTile.TPT, + (255, 255, 0): PhysTile.FIT, + } + data = list(img.getdata()) + matrix = [] + for row in range(img.height): + matrix.append([]) + for col in range(img.width): + try: + color = data[col + row*img.width][:3] + tile = dictionnary[color] # avoid alpha component + self._surf.fill(color, pygame.Rect(col*20, row*20, 20, 20)) + except: + raise ValueError("Pixel " + str(col) + "," + str(row) + " is invalid") + matrix[-1].append(tile) + return matrix + + + +def explore(matrix, x=-1, y=-1): + """explore the given matrix and change it (GRD and TPT become FIT)""" + if x < 0 and y < 0: + # searching the beginning + for row in range(len(matrix)): + for col in range(len(matrix[0])): + if matrix[row][col]: + explore(matrix, col, row) + elif matrix[y][x] in (PhysTile.TPT, PhysTile.GRD): + matrix[y][x] = PhysTile.FIT + for col, row in ((0, 1), (1, 0), (0, -1), (-1, 0)): + explore(matrix, (x+col)%len(matrix[0]), (y+row)%len(matrix)) + + +def connex(matrix, x=-1, y=-1): + """return True if the matrix is connex - has only one connexity part""" + temp = deepcopy(matrix) + explore(temp) + if any(tile in (PhysTile.GRD, PhysTile.TPT) for row in temp for tile in row): + return False + return True + +def get_one_in_digit(number): + cpt = 0 + while number: + cpt += number & 1 + number //= 2 + return cpt diff --git a/livrables/1/pacmap_maze1.png b/livrables/1/pacmap_maze1.png new file mode 100644 index 0000000000000000000000000000000000000000..503e9b941b93768c767e76ca646138a8aa94dbea GIT binary patch literal 12025 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 E0FP6mA^-pY literal 0 HcmV?d00001 diff --git a/livrables/1/pacmap_rule.txt b/livrables/1/pacmap_rule.txt new file mode 100644 index 0000000..2966272 --- /dev/null +++ b/livrables/1/pacmap_rule.txt @@ -0,0 +1,9 @@ +each wall (excluding the exterior one) have a width of at least 2 (can be filled with FIT tiles) +RGB code: +GRD 0 0 0 // ground tile +GCF 255 0 255 // ghost cell floor tile +WAL 0 0 255 // wall tile +GSD 0 255 0 // ghost door tile +GWL 0 255 255 // ghost wall tile +TPT 255 0 0 // teleporter tile +FIT 255 255 255 // fully inaccessible tile (tiles between walls) diff --git a/livrables/1/physic_engine.py b/livrables/1/physic_engine.py new file mode 100755 index 0000000..5947932 --- /dev/null +++ b/livrables/1/physic_engine.py @@ -0,0 +1,21 @@ +from pacmap import * +from pacman import * + +class PhysicEngine: + def __init__(self, c_pacmap: Map, c_pacman: Pacman): + self.pacmap = c_pacmap + self.pacman = c_pacman + self.entities = [] # ghosts + + def move_all(self): + # pacman movement + next_pac_tile = self.pacman.next_matrix_position() + pac_res = self.pacman.resolution + if self.pacman.is_at_center_tile(): + if self.pacman.next_direction != direction.none and self.pacmap.get_tile(*self.pacman.get_next_dir_tile()) in (PhysTile.GRD, PhysTile.TPT): + self.pacman.change_to_next_dir() + self.pacman.move() + elif self.pacmap.get_tile(*next_pac_tile) in (PhysTile.GRD, PhysTile.TPT): + self.pacman.move() + else: + self.pacman.move() \ No newline at end of file diff --git a/livrables/1/test_connexity.py b/livrables/1/test_connexity.py new file mode 100755 index 0000000..e9553eb --- /dev/null +++ b/livrables/1/test_connexity.py @@ -0,0 +1,45 @@ +#!/usr/bin/env python3 +import pacmap + +maps = [ + [ + [4, 1, 1, 1, 3, 1, 1, 4], + [1, 0, 0, 0, 0, 0, 0, 1], + [1, 0, 1, 1, 0, 1, 0, 1], + [3, 0, 1, 0, 0, 1, 0, 3], + [1, 0, 0, 0, 1, 0, 0, 1], + [1, 1, 1, 0, 0, 0, 1, 1], + [4, 4, 1, 1, 3, 1, 1, 4], + ], + [ + [4, 1, 1, 1, 3, 1, 1, 4], + [1, 1, 1, 1, 0, 1, 1, 1], + [1, 1, 1, 1, 0, 1, 1, 1], + [1, 1, 1, 1, 0, 1, 1, 1], + [1, 1, 1, 1, 0, 1, 1, 1], + [1, 1, 1, 1, 0, 1, 1, 1], + [4, 1, 1, 1, 3, 1, 1, 4], + ], + [ + [4, 1, 1, 1, 3, 1, 1, 4], + [1, 1, 1, 1, 0, 1, 1, 1], + [1, 1, 1, 1, 0, 1, 1, 1], + [1, 0, 0, 1, 0, 1, 1, 1], + [1, 0, 0, 1, 0, 1, 1, 1], + [1, 1, 1, 1, 0, 1, 1, 1], + [4, 1, 1, 1, 3, 1, 1, 4], + ], + [ + [4, 1, 1, 1, 3, 1, 1, 4], + [1, 1, 1, 1, 0, 1, 1, 1], + [1, 1, 1, 1, 0, 0, 0, 1], + [1, 1, 1, 1, 1, 1, 0, 1], + [3, 0, 0, 0, 0, 1, 0, 3], + [1, 1, 1, 1, 0, 1, 1, 1], + [4, 1, 1, 1, 3, 1, 1, 4], + ] +] + +for pac_map in maps: + is_connex = pacmap.connex(pac_map) + print(is_connex) \ No newline at end of file diff --git a/livrables/1/test_load_picture.py b/livrables/1/test_load_picture.py new file mode 100755 index 0000000..4266aef --- /dev/null +++ b/livrables/1/test_load_picture.py @@ -0,0 +1,13 @@ +#!/usr/bin/env python3 +from pacmap import decode_map +import sys + +if __name__ == '__main__': + if len(sys.argv) > 1: + matrix = decode_map(sys.argv[1]) + else: + matrix = decode_map("../pacmap_maze1.png") + for row in matrix: + print() + for el in row: + print(el.value, end=' ') \ No newline at end of file