0
\$\begingroup\$

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....

\$\endgroup\$
6
  • \$\begingroup\$ A question: Do you mean in the line with: # THIS LINE if 0 <= x_index < self.Size and 0 <= y_index < self.__Size: count += self.__buttons[y_index][x_index].mine if not count: self.Size or self.__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\$ Commented Apr 2, 2016 at 14:49
  • \$\begingroup\$ That won't work. In the original code, count starts out at 0, so it must have been added to at some point when it was 0. Yours never will. On a side note, you should use else:, not elif: because elif, like if, expects a condition to follow. It's like else if ... \$\endgroup\$
    – zondo
    Commented Apr 2, 2016 at 15:05
  • \$\begingroup\$ Yeah thanks. As I said. Not so familiar with python. \$\endgroup\$ Commented Apr 2, 2016 at 15:06
  • \$\begingroup\$ Something like that? \$\endgroup\$ Commented Apr 2, 2016 at 15:10
  • \$\begingroup\$ Yeah, except that count += ... in your first block and def __total... in your second block are indented by four extra spaces. My first comment about not working still applies, though. \$\endgroup\$
    – zondo
    Commented Apr 2, 2016 at 15:13

2 Answers 2

3
\$\begingroup\$

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.

\$\endgroup\$
1
  • \$\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 with UI[posx:posx+3,posy:posy+3] = 1 \$\endgroup\$ Commented Apr 2, 2016 at 16:05
0
\$\begingroup\$

This code is actually doing three things:

  1. Identifying the neighbors
  2. Counting the mines in the neighbors
  3. 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.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.