patternpythonMinor
Hungry ant AI: any food here?
Viewed 0 times
herehungryanyantfood
Problem
I'm working on a little AI to simulate ants (very basic). The full code can be found on Github. This function (in
This function works exactly as I want, but it is probably one of the ugliest I've ever seen or written. Does anyone know a way around all these nested loops?
Ants.py) takes a list of Tuples containing coordinates and tells whether or not the ant is over one of them.def Got_Food(self,all_foods):
foods = []
x,y = self.location[0],self.location[1]
c_x,c_y = self.size[0],self.size[1]
for food in all_foods:
if food[1] >= y-c_y and food[1] = c_x and food[0] y and food[1] x and food[0] y-c_y\
and food[0] > x and food[0] >x-c_y:
foods.append((food[0],food[1]))
if food[0] >= x-c_x and food[0] = y and food[1] <=y+c_y:
foods.append((food[0],food[1]))
if len(foods) == 0:
return None
return foodsThis function works exactly as I want, but it is probably one of the ugliest I've ever seen or written. Does anyone know a way around all these nested loops?
Solution
Disclaimer: Current version of the code seems to be very weirdly indented. Some comments might be wrong because of some misinterpretation of your code.
Style
Python has a style guide called PEP 8. It is usually a good idea to try to stick to it unless you have good reasons not to. In any case, it is definitly worth the read. You'll find various tools to check compliancy. In your case, the main issues would be : naming (
Design
Your function returns either a list of food or
From the Zen of Python:
Special cases aren't special enough to break the rules.
In any case, your function deserves some documentation.
Tuple unpacking
One of my favorite feature of Python is iterable unpacking. You can do something like:
and have easy access to the different elements (and an exception if the list has the wrong number of elements).
In your case, assuming
This is very convenient to avoid long expressions with error-prones bracket access to a particular index.
Going further, you could do the same with
Now, (assuming I haven't broken too many things) looks like:
Chained comparisons
From the doc:
Comparisons can be chained arbitrarily, e.g., x x` is wrong).
Style
Python has a style guide called PEP 8. It is usually a good idea to try to stick to it unless you have good reasons not to. In any case, it is definitly worth the read. You'll find various tools to check compliancy. In your case, the main issues would be : naming (
snake_case is recommended for function names), spacing (whitespace around operators), indentation (4 spaces)Design
Your function returns either a list of food or
None is there is no food. This seems to be more complicated than it should be: it could return a list of food (empty is there is no food). It makes your function easier to use, easier to explain and more concise: you can simply remove the if len(foods) == 0: condition.From the Zen of Python:
Special cases aren't special enough to break the rules.
In any case, your function deserves some documentation.
Tuple unpacking
One of my favorite feature of Python is iterable unpacking. You can do something like:
a, b, c = my_list_with_3_elementsand have easy access to the different elements (and an exception if the list has the wrong number of elements).
In your case, assuming
location and size have the wrong length, you could simply write:x, y = self.location
c_x, c_y = self.sizeThis is very convenient to avoid long expressions with error-prones bracket access to a particular index.
Going further, you could do the same with
food[0] and food[1].Now, (assuming I haven't broken too many things) looks like:
def got_food(self, all_foods):
foods = []
x, y = self.location
c_x, c_y = self.size
for f_x, f_y in all_foods:
if f_y >= y - c_y and f_y = c_x and f_x y and f_y x and f_x y - c_y and f_x > x and f_x > x - c_y:
foods.append((f_x, f_y))
if f_x >= x - c_x and f_x = y and f_y <= y + c_y:
foods.append((f_x, f_y))
return foodsChained comparisons
From the doc:
Comparisons can be chained arbitrarily, e.g., x x` is wrong).
Code Snippets
a, b, c = my_list_with_3_elementsx, y = self.location
c_x, c_y = self.sizedef got_food(self, all_foods):
foods = []
x, y = self.location
c_x, c_y = self.size
for f_x, f_y in all_foods:
if f_y >= y - c_y and f_y <= y + c_y and f_x >= c_x and f_x <= x + c_x:
if f_y > y and f_y < y + c_y and f_x > x and f_x < x + c_x:
foods.append((f_x, f_y))
elif f_y < y and f_y > y - c_y and f_x > x and f_x > x - c_y:
foods.append((f_x, f_y))
if f_x >= x - c_x and f_x <= x + c_x and f_y >= y and f_y <= y + c_y:
foods.append((f_x, f_y))
return foodsdef got_food(self, all_foods):
foods = []
x, y = self.location
c_x, c_y = self.size
for f_x, f_y in all_foods:
if y - c_y <= f_y <= y + c_y and c_x <= f_x <= x + c_x:
if y < f_y < y + c_y and x < f_x < x + c_x:
foods.append((f_x, f_y))
elif y > f_y > y - c_y and f_x > x and f_x > x - c_y:
foods.append((f_x, f_y))
if x - c_x <= f_x <= x + c_x and y <= f_y <= y + c_y:
foods.append((f_x, f_y))
return foodsContext
StackExchange Code Review Q#126910, answer score: 5
Revisions (0)
No revisions yet.