Is there any smart way to compress the following code:
def __total(self, x, y):
count = 0
for x_offset in range(-1, 2):
x_index = x + x_offset
for y_offset in range(-1, 2):
y_index = y + y_offset
if 0 <= x_index < self.Size and 0 <= y_index < self.__Size:
count += self.__buttons[y_index][x_index].mine
if not count:
for x_offset in range(-1, 2):
x_index = x + x_offset
for y_offset in range(-1, 2):
y_index = y + y_offset
if 0 <= x_index < self.__Size and 0 <= y_index < self.__Size:
self.__push(x_index, y_index)
return count
I have been trying forever with an extreme "coder-blackout" not being able to succeed....
2 Answers 2
Okay. Improved my answer. You can call this code as normal with self.__total(x,y)
. In my own test, it showed the exact same results as your code has.
def __total(self, x, y, count=0, old=False):
if (not count and old) or not old:
for x_index in range(-1+x, 2+x):
for y_index in range(-1+y, 2+y):
if 0 <= x_index < self.__Size and 0 <= y_index < self.__Size:
if old:
self.__push(x_index, y_index)
else:
count += self.__buttons[y_index][x_index].mine
if old:
return count
return self.__total(x,y, count, True)
Another solution would be using Numpy:
import numpy as np
def __total(self, x,y):
count = np.sum( self.__buttons[ x-1 if x>0 else 0:x+2, y-1 if y>0 else 0:y+2 ] )
if not count:
for x_offset in range(-1, 2):
x_index = x + x_offset
for y_offset in range(-1, 2):
y_index = y + y_offset
if 0 <= x_index < self.__Size and 0 <= y_index < self.__Size:
self.__push(x_index, y_index)
return count
The problem with this code is, that you can't use array class, but would need a Numpy array of all mines in a extra variable. But it would speed up your calculations just because of the nature of Numpy.
-
\$\begingroup\$ I understand what the code is doing. The question for optimisation is: Could you do instead of a
__push
maybe just a give a array. With that you could easily filter an area and change all the values on it. Example: UI is your array that represents the player field: You can easily change with that all the values in the range to 1 withUI[posx:posx+3,posy:posy+3] = 1
\$\endgroup\$Georg Friedrich– Georg Friedrich2016年04月02日 16:05:26 +00:00Commented Apr 2, 2016 at 16:05
This code is actually doing three things:
- Identifying the neighbors
- Counting the mines in the neighbors
- Conditionally opening up the neighbors (I think that's what you intend?)
Therefore, you would be better served with three functions. The fundamental one is:
def neighbors(self, x, y):
for xx in (x - 1, x, x + 1):
if not (0 <= xx < self.Size): continue
for yy in (y - 1, y, y + 1):
if not (0 <= yy < self.__Size): continue
yield xx, yy
Then you could write (2) and (3) like:
mine_count = sum(self.__buttons[yy][xx].mine for xx, yy in self.neighbors(x, y))
Note that self.Size
violates PEP 8 naming conventions, and the similarity with self.__Size
is confusing. Also, your use of double-underscores is probably inappropriate.
self.Size
orself.__Size
? Okay. I will assume for now, that you meant__Size
. def __total(self, x, y, count, old): if (not count and old) or not old: for x_index in range(-1+x, 2+x): for y_index in range(-1+y, 2+y): if 0 <= x_index < self.Size and 0 <= y_index < self.__Size: if old: self.__push(x_index, y_index) else: count += self.__bu \$\endgroup\$count
starts out at0
, so it must have been added to at some point when it was0
. Yours never will. On a side note, you should useelse:
, notelif:
becauseelif
, likeif
, expects a condition to follow. It's likeelse if ...
\$\endgroup\$count += ...
in your first block anddef __total...
in your second block are indented by four extra spaces. My first comment about not working still applies, though. \$\endgroup\$