Merge pull request 'a-star-implementation' (#22) from a-star-implementation into main
Reviewed-on: #22 Reviewed-by: Tim Barvenov <timbar@st.amu.edu.pl>
This commit is contained in:
commit
ddb69cc1ec
113
AI_brain/rotate_and_go_astar.py
Normal file
113
AI_brain/rotate_and_go_astar.py
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
import heapq
|
||||||
|
from domain.world import World
|
||||||
|
|
||||||
|
|
||||||
|
class State:
|
||||||
|
def __init__(self, x, y, direction=(1, 0), entity=None):
|
||||||
|
self.x = x
|
||||||
|
self.y = y
|
||||||
|
self.direction = direction
|
||||||
|
|
||||||
|
|
||||||
|
def __hash__(self):
|
||||||
|
return hash((self.x, self.y))
|
||||||
|
|
||||||
|
def __eq__(self, other):
|
||||||
|
return (
|
||||||
|
self.x == other.x
|
||||||
|
and self.y == other.y
|
||||||
|
and self.direction == other.direction
|
||||||
|
)
|
||||||
|
|
||||||
|
def heuristic(self, goal_state):
|
||||||
|
return abs(self.x - goal_state.x) + abs(self.y - goal_state.y)
|
||||||
|
|
||||||
|
|
||||||
|
class Node:
|
||||||
|
def __init__(self, state: State, g_score: int, goal_state: State):
|
||||||
|
self.state = state
|
||||||
|
self.g_score = g_score
|
||||||
|
self.f_score = g_score + state.heuristic(goal_state)
|
||||||
|
self.parent = None
|
||||||
|
self.action = None
|
||||||
|
|
||||||
|
def __lt__(self, other):
|
||||||
|
return self.f_score < other.f_score
|
||||||
|
|
||||||
|
|
||||||
|
def action_sequence(node: Node):
|
||||||
|
actions = []
|
||||||
|
while node.parent:
|
||||||
|
actions.append(node.action)
|
||||||
|
node = node.parent
|
||||||
|
actions.reverse()
|
||||||
|
return actions
|
||||||
|
|
||||||
|
|
||||||
|
class RotateAndGoAStar:
|
||||||
|
def __init__(self, world: World, start_state: State, goal_state: State):
|
||||||
|
self.world = world
|
||||||
|
self.start_state = start_state
|
||||||
|
self.goal_state = goal_state
|
||||||
|
self.fringe = []
|
||||||
|
self.enqueued_states = set()
|
||||||
|
self.explored = set()
|
||||||
|
self.actions = []
|
||||||
|
|
||||||
|
def get_g_score(self, state):
|
||||||
|
return self.world.get_cost(state.x, state.y)
|
||||||
|
|
||||||
|
def search(self):
|
||||||
|
heapq.heappush(
|
||||||
|
self.fringe, Node(self.start_state, 0, self.goal_state)
|
||||||
|
)
|
||||||
|
|
||||||
|
while self.fringe:
|
||||||
|
elem = heapq.heappop(self.fringe)
|
||||||
|
if self.is_goal(elem.state):
|
||||||
|
self.actions = action_sequence(elem)
|
||||||
|
return True
|
||||||
|
self.explored.add(elem.state)
|
||||||
|
|
||||||
|
for action, state in self.successors(elem.state):
|
||||||
|
if state in self.explored:
|
||||||
|
continue
|
||||||
|
|
||||||
|
new_g_score = new_g_score = elem.g_score + self.world.get_cost(state.x, state.y)
|
||||||
|
if state not in self.enqueued_states:
|
||||||
|
next_node = Node(state, new_g_score, self.goal_state)
|
||||||
|
next_node.action = action
|
||||||
|
next_node.parent = elem
|
||||||
|
heapq.heappush(self.fringe, next_node)
|
||||||
|
self.enqueued_states.add(state)
|
||||||
|
elif new_g_score < self.get_g_score(state):
|
||||||
|
for node in self.fringe:
|
||||||
|
if node.state == state:
|
||||||
|
node.g_score = new_g_score
|
||||||
|
node.f_score = (
|
||||||
|
new_g_score + node.state.heuristic(self.goal_state)
|
||||||
|
)
|
||||||
|
node.parent = elem
|
||||||
|
node.action = action
|
||||||
|
heapq.heapify(self.fringe)
|
||||||
|
break
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
|
def successors(self, state: State):
|
||||||
|
new_successors = [
|
||||||
|
("RR", State(state.x, state.y, (-state.direction[1], state.direction[0]))),
|
||||||
|
("RL", State(state.x, state.y, (state.direction[1], -state.direction[0]))),
|
||||||
|
]
|
||||||
|
next_x = state.x + state.direction[0]
|
||||||
|
next_y = state.y + state.direction[1]
|
||||||
|
if self.world.accepted_move(next_x, next_y):
|
||||||
|
new_successors.append(
|
||||||
|
("GO", State(next_x, next_y, state.direction))
|
||||||
|
)
|
||||||
|
return new_successors
|
||||||
|
|
||||||
|
def is_goal(self, state: State) -> bool:
|
||||||
|
return (
|
||||||
|
state.x == self.goal_state.x
|
||||||
|
and state.y == self.goal_state.y )
|
@ -56,3 +56,5 @@ Summary:
|
|||||||
The "Automatic cleaning robot" project is a simple yet educational programming project. Users are tasked with specifying the positions that the robot should clean, as well as the coordinates of obstacles. The robot, built using artificial intelligence, is responsible for avoiding obstacles, making decisions in case of random events, and cleaning the designated points. The project was written in Python with the use of artificial intelligence. The analysis of images is based on neural networks.
|
The "Automatic cleaning robot" project is a simple yet educational programming project. Users are tasked with specifying the positions that the robot should clean, as well as the coordinates of obstacles. The robot, built using artificial intelligence, is responsible for avoiding obstacles, making decisions in case of random events, and cleaning the designated points. The project was written in Python with the use of artificial intelligence. The analysis of images is based on neural networks.
|
||||||
|
|
||||||
******
|
******
|
||||||
|
******
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@ from domain.entities.entity import Entity
|
|||||||
|
|
||||||
class World:
|
class World:
|
||||||
def __init__(self, width: int, height: int) -> object:
|
def __init__(self, width: int, height: int) -> object:
|
||||||
|
self.costs = [[1000 for j in range(height)] for i in range(width)]
|
||||||
self.width = width
|
self.width = width
|
||||||
self.height = height
|
self.height = height
|
||||||
self.dust = [[[] for j in range(height)] for i in range(width)]
|
self.dust = [[[] for j in range(height)] for i in range(width)]
|
||||||
@ -53,3 +54,5 @@ class World:
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
def get_cost(self, x, y):
|
||||||
|
return self.costs[x][y]
|
17
main.py
17
main.py
@ -14,7 +14,8 @@ from domain.entities.docking_station import Doc_Station
|
|||||||
from domain.world import World
|
from domain.world import World
|
||||||
from view.renderer import Renderer
|
from view.renderer import Renderer
|
||||||
# from AI_brain.movement import GoAnyDirectionBFS, State
|
# from AI_brain.movement import GoAnyDirectionBFS, State
|
||||||
from AI_brain.rotate_and_go_bfs import RotateAndGoBFS, State
|
# from AI_brain.rotate_and_go_bfs import RotateAndGoBFS, State
|
||||||
|
from AI_brain.rotate_and_go_astar import RotateAndGoAStar, State
|
||||||
|
|
||||||
|
|
||||||
config = configparser.ConfigParser()
|
config = configparser.ConfigParser()
|
||||||
@ -52,7 +53,8 @@ class Main:
|
|||||||
end_state = State(self.world.doc_station.x, self.world.doc_station.y)
|
end_state = State(self.world.doc_station.x, self.world.doc_station.y)
|
||||||
|
|
||||||
# path_searcher = GoAnyDirectionBFS(self.world, start_state, end_state)
|
# path_searcher = GoAnyDirectionBFS(self.world, start_state, end_state)
|
||||||
path_searcher = RotateAndGoBFS(self.world, start_state, end_state)
|
# path_searcher = RotateAndGoBFS(self.world, start_state, end_state)
|
||||||
|
path_searcher = RotateAndGoAStar(self.world, start_state, end_state)
|
||||||
if not path_searcher.search():
|
if not path_searcher.search():
|
||||||
print("No solution")
|
print("No solution")
|
||||||
exit(0)
|
exit(0)
|
||||||
@ -134,7 +136,7 @@ class Main:
|
|||||||
|
|
||||||
def generate_world(tiles_x: int, tiles_y: int) -> World:
|
def generate_world(tiles_x: int, tiles_y: int) -> World:
|
||||||
world = World(tiles_x, tiles_y)
|
world = World(tiles_x, tiles_y)
|
||||||
for _ in range(10):
|
for _ in range(35):
|
||||||
temp_x = randint(0, tiles_x - 1)
|
temp_x = randint(0, tiles_x - 1)
|
||||||
temp_y = randint(0, tiles_y - 1)
|
temp_y = randint(0, tiles_y - 1)
|
||||||
world.add_entity(Garbage(temp_x, temp_y))
|
world.add_entity(Garbage(temp_x, temp_y))
|
||||||
@ -149,9 +151,16 @@ def generate_world(tiles_x: int, tiles_y: int) -> World:
|
|||||||
world.add_entity(Entity(8, 8, "PLANT2"))
|
world.add_entity(Entity(8, 8, "PLANT2"))
|
||||||
world.add_entity(Entity(9, 3, "PLANT3"))
|
world.add_entity(Entity(9, 3, "PLANT3"))
|
||||||
world.add_entity(Earring(5, 5))
|
world.add_entity(Earring(5, 5))
|
||||||
return world
|
|
||||||
|
|
||||||
|
|
||||||
|
for x in range(world.width):
|
||||||
|
for y in range(world.height):
|
||||||
|
if world.is_garbage_at(x, y):
|
||||||
|
world.costs[x][y] = 1
|
||||||
|
else:
|
||||||
|
world.costs[x][y] = 10
|
||||||
|
return world
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
app = Main()
|
app = Main()
|
||||||
if config["APP"]["movement"] == "human":
|
if config["APP"]["movement"] == "human":
|
||||||
|
Loading…
Reference in New Issue
Block a user