Skip to content

Commit

Permalink
Bee remembers its path
Browse files Browse the repository at this point in the history
  • Loading branch information
HokageM committed Feb 24, 2024
1 parent 8bebac5 commit 0f1000a
Show file tree
Hide file tree
Showing 7 changed files with 402 additions and 107 deletions.
18 changes: 17 additions & 1 deletion src/ninjabees/Animator.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,34 @@


class Animator:
"""
Class to handle the animation of the world map.
"""

def __init__(self):
pass

@staticmethod
def clear_terminal():
"""
Clear the terminal.
:return:
"""
os.system('clear' if os.name == 'posix' else 'cls')

@staticmethod
def print_world_status(world_map, found, total):
def print_world_status(world_map, found, total, food_at_hive):
"""
Print the status of the world map.
:param world_map:
:param found:
:param total:
:return:
"""
Animator.clear_terminal()
for row in world_map:
print(''.join(row))

print(f'Found Food Sources: {found} of {total}')
print(f'Food at Hive: {food_at_hive}')
time.sleep(0.09)
247 changes: 195 additions & 52 deletions src/ninjabees/Bee.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,119 +5,262 @@


class BeeJob(Enum):
"""
This class represents the job of a bee.
"""
Scout = 0
Forager = 1


class Bee(Entity):
def __init__(self, name, hive, world, exploration_radius=1, move_range=5):
"""
This class represents a bee.
"""

ENERGY = 600

def __init__(self, name, hive, world, exploration_radius=0):
super().__init__(hive.get_x(), hive.get_y(), EntityType.Bee)

self.name = name
self.hive = hive
self.world = world

self.__energy = Bee.ENERGY

# Initially no food source is known
self.__job = BeeJob.Scout
self.__food_goal = None

self.__exploration_radius = exploration_radius
self.__move_range = move_range

self.__found_food = False
self.__found_food_source = None
self.debug_path = []
self.debug_pos = [(hive.get_x(), hive.get_y())]

self.__home_path = []
self.__home_path_index = 0
self.__flying_path = []
self.__flying_index = 0
self.__is_path_set_to_hive = False

self.wait_for_instructions = False

def has_found_food(self):
"""
Check if the bee has found food.
:return:
"""
return self.__found_food

def get_food_goal(self):
"""
Get the food goal for the bee.
:return:
"""
return self.__food_goal

def get_found_food_source(self):
"""
Get the found food source.
:return:
"""
return self.__found_food_source

def get_job(self):
"""
Get the job of the bee.
:return:
"""
return self.__job

def set_job(self, job):
"""
Set the job for the bee.
:param job:
:return:
"""
self.__job = job

def set_food_goal(self, food_goal):
def get_flying_path(self):
"""
Get the flying path.
:return:
"""
return self.__flying_path

def get_flying_index(self):
"""
Get the flying index.
:return:
"""
return self.__flying_index

def set_flying_path(self, path):
"""
Set the flying path.
:param path:
:return:
"""
self.__flying_path = path

def set_food_goal(self, food_goal, path_to_food):
"""
Set the food goal for the bee.
:param food_goal:
:param path_to_food:
:return:
"""
self.__food_goal = food_goal
self.__flying_path = path_to_food

def explore(self):
if self.__food_goal and self.__job != BeeJob.Scout:
self.move_towards_exploration_goal()
"""
Explore the environment to find food sources.
:return:
"""
if self.__energy == 0 or self.__found_food:
self.return_home()
return
nearby_sources = [source for source in self.world.get_unclaimed_food_sources() if self.is_within_radius(source)]
if nearby_sources:
selected_source = random.choice(nearby_sources)
self.__found_food = True
self.__found_food_source = selected_source
else:
self.move()
self.__energy -= 1

if self.__job == BeeJob.Scout:
food_source = self.world.get_unclaimed_food_source_at(self.get_x(), self.get_y())
if food_source:
self.__found_food = True
self.__found_food_source = food_source
else:
self.move()
return

self.move_towards_exploration_goal()
return

def is_within_radius(self, food_source):
distance = ((self.get_x() - food_source.get_x()) ** 2 + (self.get_y() - food_source.get_y()) ** 2) ** 0.5
return distance <= self.__exploration_radius
"""
Check if the bee is within the exploration radius of a food source.
:param food_source:
:return:
"""
return self.get_x() == food_source.get_x() and self.get_y() == food_source.get_y()

def return_home(self):
"""
Move the bee back to the hive.
:return:
"""
x = self.get_x()
y = self.get_y()

if x == self.hive.get_x() and y == self.hive.get_y():
if self.__found_food_source not in self.hive.food_sources:
self.hive.add_found_food_source(self.__found_food_source)
self.__found_food = False
self.__found_food_source = None
self.__food_goal = None
else:
if x != self.hive.get_x():
if (x - self.hive.get_x()) > 0:
self.set_x(x - 1)
else:
self.set_x(x + 1)
if y != self.hive.get_y():
if (y - self.hive.get_y()) > 0:
self.set_y(y - 1)
else:
self.set_y(y + 1)
if self.__found_food:
self.__is_path_set_to_hive = False
self.hive.add_found_food_source(self.__found_food_source, list(self.__flying_path))
self.wait_for_instructions = True
return

if not self.__is_path_set_to_hive:
self.__is_path_set_to_hive = True
self.reverse_flying_path()

move = self.__home_path[self.__home_path_index]
self.__home_path_index += 1
x += move[0]
y += move[1]
self.set_x(x)
self.set_y(y)

def move_towards_exploration_goal(self):
"""
Move the bee towards the food goal.
:return:
"""
x = self.get_x()
y = self.get_y()

if x == self.__food_goal.get_x() and y == self.__food_goal.get_y():
self.__found_food = True
self.__found_food_source = self.__food_goal
self.__found_food = True
self.__food_goal = None
else:
if x != self.__food_goal.get_x():
if (x - self.__food_goal.get_x()) > 0:
self.set_x(x - 1)
else:
self.set_x(x + 1)
if y != self.__food_goal.get_y():
if (y - self.__food_goal.get_y()) > 0:
self.set_y(y - 1)
else:
self.set_y(y + 1)
self.__flying_index = 0
return

move = self.__flying_path[self.__flying_index]
self.debug_path.append((move[0], move[1]))
self.__flying_index += 1
x += move[0]
y += move[1]
self.set_x(x)
self.set_y(y)
self.debug_pos.append((self.get_x(), self.get_y()))

def move(self):
"""
Move the bee in a random direction within a certain range.
:return:
"""
x = self.get_x()
y = self.get_y()

x += int(random.uniform(-self.__move_range, self.__move_range))
y += int(random.uniform(-self.__move_range, self.__move_range))
move_x = random.randint(-1, 1)
move_y = random.randint(-1, 1)

self.set_x(x)
self.set_y(y)
x += move_x
y += move_y

if x < 0:
self.set_x(0)
x = 0
move_x = 0
if y < 0:
self.set_y(0)
if x > 89:
self.set_x(89)
if y > 199:
self.set_y(199)
y = 0
move_y = 0
if x > 199:
x = 199
move_x = 0
if y > 89:
y = 89
move_y = 0

if move_x == 0 and move_y == 0:
self.move()
return

self.set_x(x)
self.set_y(y)

self.__flying_path.append((move_x, move_y))
# self.__flying_path.add_step(move_x, move_y)

def reset(self):
"""
Reset the bee.
:return:
"""
self.set_x(self.hive.get_x())
self.set_y(self.hive.get_y())

self.__found_food = False
self.__found_food_source = None
self.__food_goal = None
self.__is_path_set_to_hive = False
self.__energy = Bee.ENERGY

self.__home_path = []
self.__home_path_index = 0
self.__flying_path = []
self.__flying_index = 0

self.debug_path = []
self.debug_pos = [(self.hive.get_x(), self.hive.get_y())]

def reverse_flying_path(self):
"""
Reverse the flying path.
:return:
"""
reverse_path = []
for move in self.__flying_path:
reverse_path.append((-move[0], -move[1]))
reverse_path.reverse()
self.__home_path = list(reverse_path)
8 changes: 8 additions & 0 deletions src/ninjabees/FoodSource.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,18 @@


class FoodSource(Entity):
"""
This class represents a food source.
"""

def __init__(self, name, nutritional_val, x, y):
super().__init__(x, y, EntityType.Food)
self.nutritional_val = nutritional_val
self.amount = 100

def get_amount(self):
"""
Get the amount of food in the food source.
:return:
"""
return self.amount
Loading

0 comments on commit 0f1000a

Please sign in to comment.