diff --git a/.idea/Projekt_AI-Automatyczny_saper.iml b/.idea/Projekt_AI-Automatyczny_saper.iml index 4c879079..74d515a0 100644 --- a/.idea/Projekt_AI-Automatyczny_saper.iml +++ b/.idea/Projekt_AI-Automatyczny_saper.iml @@ -4,7 +4,7 @@ - + \ No newline at end of file diff --git a/Engine/Agent.py b/Engine/Agent.py index 063a7f2c..73e7cda9 100644 --- a/Engine/Agent.py +++ b/Engine/Agent.py @@ -6,6 +6,7 @@ class Agent(object): def __init__(self, point): self.point = point self.image = pygame.image.load('Engine/agent.png') + self.orientation = 0 def getPoint(self): return self.point @@ -13,6 +14,23 @@ class Agent(object): def defuse(self, bomb): bomb.isDefused = True + def rotateImage(self, orientation): + angle = self.getAngle(orientation) + self.image = pygame.transform.rotate(self.image, 360 - self.orientation) + self.image = pygame.transform.rotate(self.image, angle) + self.orientation = angle + + def getAngle(self,orientation): + if self.point.getX() < orientation.getX(): + return 0 + elif self.point.getY() > orientation.getY(): + return 90 + elif self.point.getX() > orientation.getX(): + return 180 + elif self.point.getY() < orientation.getY(): + return 270 + return 0 + # def ifNotOnEdge(self, destination): # if destination == UP: # if self.x - 1 <= 0: diff --git a/Engine/BfsPathFinder.py b/Engine/BfsPathFinder.py new file mode 100644 index 00000000..2b603506 --- /dev/null +++ b/Engine/BfsPathFinder.py @@ -0,0 +1,43 @@ +from queue import Queue +from Engine.PathFinder import PathFinder +class BfsPathFinder(PathFinder): + + def __init__(self, board): + super().__init__(board) + self.board = board + self.goal = None + def findBomb(self,start): + + frontier = Queue() + frontier.put(start) + cameFrom = dict() + cameFrom[start] = None + + while not frontier.empty(): + current = frontier.get() + + if self.checkGoal(current): + return self.constructPath(cameFrom,start) + + for next in self.getNeighbour(current): + if next not in cameFrom: + frontier.put(next) + cameFrom[next] = current + return [] + + def constructPath(self,cameFrom,start): + current = cameFrom[self.goal] + path = [] + path.append(self.goal) + while current != start: + path.append(current) + current = cameFrom[current] + path.append(start) + path.reverse() + return path + + def checkGoal(self, current): + if current in self.board.bombMap: + self.goal = current + return True + return False diff --git a/Engine/Board.py b/Engine/Board.py index d837a6b0..b07afa93 100644 --- a/Engine/Board.py +++ b/Engine/Board.py @@ -8,6 +8,7 @@ class Board: def __init__(self, win): self.board = [] self.bombMap = {} + self.stoneMap = {} self.win = win def drawSquares(self, win): @@ -33,6 +34,14 @@ class Board: rect.center = (key.getX() * SQUARE_SIZE + SQUARE_SIZE / 2, key.getY() * SQUARE_SIZE + SQUARE_SIZE / 2) self.win.blit(image, rect) + def drawStones(self): + for key in self.stoneMap: + image = pygame.image.load('Engine/stone.png') + image = pygame.transform.scale(image, (SQUARE_SIZE - 5, SQUARE_SIZE - 5)) + rect = image.get_rect() + rect.center = (key.getX() * SQUARE_SIZE + SQUARE_SIZE / 2, key.getY() * SQUARE_SIZE + SQUARE_SIZE / 2) + self.win.blit(image, rect) + def getBomb(self, point): if point in self.bombMap: return self.bombMap[point] diff --git a/Engine/Game.py b/Engine/Game.py index c91e31c8..bc893f45 100644 --- a/Engine/Game.py +++ b/Engine/Game.py @@ -8,6 +8,8 @@ from Engine.Agent import Agent from Engine.BombFactory import BombFactory from Engine.Point import Point from Engine.Stone import Stone +from Engine.PathFinder import PathFinder +from Engine.BfsPathFinder import BfsPathFinder class Game: @@ -22,40 +24,63 @@ class Game: self.agent = Agent(Point(0, 0)) self.turn = GREEN self.goingDown = True + self.path = [] def update(self): - self.agent.defuse(self.board.getBomb(self.agent.getPoint())) + self.defuseBomb() self.board.drawSquares(self.win) self.board.drawBombs() + self.board.drawStones() self.board.drawAgent(self.win, self.agent) pygame.display.update() - def move(self): - point = self.agent.getPoint() - if self.goingDown: - if point.getY() + 1 < ROWS: - point.y += 1 - elif point.getX() + 1 < COLS: - point.x += 1 - self.goingDown = not self.goingDown - else: - if point.getY() - 1 >= 0: - point.y -= 1 - elif point.getX() + 1 < COLS: - point.x += 1 - self.goingDown = not self.goingDown - self.agent.point = point + # def move(self): + # point = self.agent.getPoint() + # tmpPoint = Point(point.getX(), point.getY()) + # if self.goingDown: + # if point.getY() + 1 < ROWS: + # tmpPoint.y += 1 + # elif point.getX() + 1 < COLS: + # tmpPoint.x += 1 + # self.goingDown = not self.goingDown + # else: + # if point.getY() - 1 >= 0: + # tmpPoint.y -= 1 + # elif point.getX() + 1 < COLS: + # tmpPoint.x += 1 + # self.goingDown = not self.goingDown + # self.agent.rotateImage(tmpPoint) + # self.agent.point = tmpPoint + # #self.moveSequence() + # + # def moveSequence(self): + # pathfinder = PathFinder(self.board) + # for point in pathfinder.findPath(Point(0,0), Point(5,5)): + # self.agent.point = point + # self.update() + def randomizeObject(self): i = 0 - while i < 11: - point = Point(random.randint(0, 7), random.randint(0, 7)) + while i < 10: + point = Point(random.randint(0, 9), random.randint(0, 9)) if(point.getX() == 0 and point.getY() == 0): continue; if point not in self.board.bombMap: object = self.pickObject(random.randint(0, 4)) self.board.bombMap[point] = object i += 1 + r = 5 + j = 0 + while j < r: + point = Point(random.randint(0, 9), random.randint(0, 9)) + if (point.getX() == 0 and point.getY() == 0): + continue; + if point not in self.board.bombMap and point not in self.board.stoneMap: + object = Stone() + self.board.stoneMap[point] = object + j += 1 + def pickObject(self, rand): if rand == 0: @@ -68,5 +93,28 @@ class Game: return BombFactory.create(CLAYMORE) elif rand == 4: return BombFactory.create(LAND_MINE) - # elif(rand == 5): - # return Stone() + + def findBomb(self): + return BfsPathFinder(self.board).findBomb(self.agent.getPoint()) + + def finalState(self): + if len(self.board.bombMap) == 0: + return True + return False + + def moveToNext(self): + point = self.path.pop(0) + self.agent.rotateImage(point) + self.agent.point = point + + def savePath(self,path): + self.path = path + + def getPath(self): + return self.path + + def defuseBomb(self): + point = self.agent.getPoint() + self.agent.defuse(self.board.getBomb(point)) + if point in self.board.bombMap: + self.board.bombMap.pop(point) diff --git a/Engine/PathFinder.py b/Engine/PathFinder.py new file mode 100644 index 00000000..06d65bc8 --- /dev/null +++ b/Engine/PathFinder.py @@ -0,0 +1,81 @@ +from Constants import ROWS, COLS +from Engine.Point import Point + + +class PathFinder: + + def __init__(self, board): + self.board = board + self.openList = [] + self.cameFrom = {} + self.gScore = {} + self.fScore = {} + self.current = Point(0,0) + + + def findPath(self,startPoint, endPoint): + self.openList.append(startPoint) + self.gScore[startPoint] = 0 + self.fScore[startPoint] = startPoint.distance(endPoint) + + while self.openList: + self.current = self.minKey(self.fScore, self.openList) + + if self.current.__eq__(endPoint): + return self.reconstructPath() + + self.openList.remove(self.current) + + for point in self.getNeighbour(self.current): + tentativeGScore = self.gScore.get(self.current) + self.current.distance(point) + if tentativeGScore < self.gScore.get(point, 10000): + self.cameFrom[point] = self.current + self.gScore[point] = tentativeGScore + self.fScore[point] = point.distance(startPoint) + if(point not in self.openList): + self.openList.append(point) + return [] + + def reconstructPath(self): + totalPath = [] + totalPath.append(self.current) + while self.current in self.cameFrom: + self.current = self.cameFrom[self.current] + totalPath.insert(0,self.current) + return totalPath + + def getNeighbour(self, current): + neighbourlist = [] + point1 = Point(current.getX() + 1, current.getY()) + point2 = Point(current.getX(), current.getY() + 1) + point3 = Point(current.getX(), current.getY() - 1) + point4 = Point(current.getX() - 1, current.getY()) + if self.checkField(current,point1): + neighbourlist.append(point1) + if self.checkField(current, point2): + neighbourlist.append(point2) + if self.checkField(current,point3): + neighbourlist.append(point3) + if self.checkField(current,point4): + neighbourlist.append(point4) + return neighbourlist + + def checkField(self,current, point): + if not (point.getX() < 0 or point.getX() > COLS - 1 or point.getY() < 0 or point.getY() > ROWS - 1 or point.__eq__(current)) and point not in self.board.stoneMap: + return True + return False + + def minKey(self, fscore, openlist): + minkey = Point(0,0) + minValue = float('inf') + for point in openlist: + value = fscore.get(point, 10000) + if value < minValue: + minValue = value + minkey = point + return minkey + + + + + diff --git a/Engine/Point.py b/Engine/Point.py index 3d872721..0f15323e 100644 --- a/Engine/Point.py +++ b/Engine/Point.py @@ -9,6 +9,9 @@ class Point: def getX(self): return self.x + def distance(self,endpoint): + return abs(self.getX() + endpoint.getX()) + abs(self.getY() + endpoint.getY()) + def __hash__(self): """Overrides the default implementation""" return hash(tuple(sorted(self.__dict__.items()))) diff --git a/Engine/__pycache__/Agent.cpython-39.pyc b/Engine/__pycache__/Agent.cpython-39.pyc index c3773505..a81294fb 100644 Binary files a/Engine/__pycache__/Agent.cpython-39.pyc and b/Engine/__pycache__/Agent.cpython-39.pyc differ diff --git a/Engine/__pycache__/BfsPathFinder.cpython-39.pyc b/Engine/__pycache__/BfsPathFinder.cpython-39.pyc new file mode 100644 index 00000000..5c5a53e3 Binary files /dev/null and b/Engine/__pycache__/BfsPathFinder.cpython-39.pyc differ diff --git a/Engine/__pycache__/Board.cpython-39.pyc b/Engine/__pycache__/Board.cpython-39.pyc index 15460151..bde93dbf 100644 Binary files a/Engine/__pycache__/Board.cpython-39.pyc and b/Engine/__pycache__/Board.cpython-39.pyc differ diff --git a/Engine/__pycache__/Game.cpython-39.pyc b/Engine/__pycache__/Game.cpython-39.pyc index 50d4b9a5..0ffd955a 100644 Binary files a/Engine/__pycache__/Game.cpython-39.pyc and b/Engine/__pycache__/Game.cpython-39.pyc differ diff --git a/Engine/__pycache__/PathFinder.cpython-39.pyc b/Engine/__pycache__/PathFinder.cpython-39.pyc new file mode 100644 index 00000000..565e51ee Binary files /dev/null and b/Engine/__pycache__/PathFinder.cpython-39.pyc differ diff --git a/Engine/__pycache__/Point.cpython-39.pyc b/Engine/__pycache__/Point.cpython-39.pyc index 91544579..f1fc8ec4 100644 Binary files a/Engine/__pycache__/Point.cpython-39.pyc and b/Engine/__pycache__/Point.cpython-39.pyc differ diff --git a/main.py b/main.py index 2566a440..ea83ec1f 100644 --- a/main.py +++ b/main.py @@ -20,7 +20,12 @@ def main(): run = False pygame.time.delay(200) - game.move() + if game.finalState(): + break + if len(game.getPath()) == 0: + path = game.findBomb() + game.savePath(path) + game.moveToNext() game.update()