On 01/03/2015 10:09 AM, Steven D'Aprano wrote:
On Fri, Jan 02, 2015 at 09:00:22PM -0500, WolfRage wrote:
Python3.4+ Linux Mint 17.1 but the code will be cross platform (Mobile,
Windows, Linux, OSX).

First an explanation of how the game works: The game is a simple
matching game but with a twist. Instead of matching a straight 3 in a
row, we have some rules that only certain combinations will result in an
elimination. In general 2 of the same value in a row with with 1 of 2
other possible values will eliminate all three nodes.

Do you mean "1 of 2" or "1 or 2"?
1 of 2.


Eliminations can
occur either horizontally or vertically but not diagonally. Each tile
has a value now, that value is used when evaluating the rules. Currently
there are only 5 allowed values of 0-4 although more could be added
later, so any solution needs to be expandable.

Okay, so the values are 0, 1, 2, 3, and 4. This doesn't match your code
belong. Is the code wrong or your description?

My description was wrong, I am sorry I had started to simplify my code when I was first writing this, but realized that ruined my algorithm for finding matches.That is probably where I confused Dave.

These are the basic rules that allow for an elimination to occur(values
are put in quotes to distinguish values):
2 "5"s followed or proceeded by a "19" will eliminate all 3 nodes.
[...]

Since neither 5 nor 19 is a possible value, this can never apply.

Sorry again, these are actually the correct values. But my earlier mistake misleads on this section that is actually correct.

All the other rules you give include values greater than 4, and likewise
can never apply. That means that no eliminations are ever possible. I
think your description needs some work :-)

Yes. Sorry. Let me re-do that.

First an explanation of how the game works: The game is a simple
matching game but with a twist. Instead of matching a straight 3 in a
row, we have some rules that only certain combinations will result in an elimination. In general 2 of the same value in a row with with 1 of 2
other possible values will eliminate all three nodes. Eliminations can
occur either horizontally or vertically but not diagonally. Each tile
has a value now, that value is used when evaluating the rules. Currently there are only 5 allowed values of [5, 6, 11, 19, 20] although more could be added [52, 61, 67, etc] later, so any solution needs to be expandable.
The remainder of the explanation was correct. Sorry about that.


class GameTile():
[...]
     def __str__(self):
         #return '%d, %d' % (self.col, self.row)
         if len(str(self.value)) == 1:
             return ' ' + str(self.value)
         return str(self.value)

Eliminate comments which no longer apply. Don't use them for keeping
old, obsolete or wrong code.

OK, good point, I should be using my bzr revision control.

This method can be better written like this:

     def __str__(self):
         return "%2d" % self.value

I was switching between the 2 implementations of __str__ when I was testing some new code, but now need. I will just make it concrete and then directly request any other values.

class GameGrid():
     def __init__(self, cols=8, rows=7, **kwargs):
         self.cols = cols
         self.rows = rows
         self.make_grid()

     def make_grid(self):
         # grid is 2d array as x, y ie [x][y].
         self.grid = []
         for row_num in range(self.rows):
             self.grid.append([GameTile(value=random.choice([5, 6, 11,
19, 20]), col=col_num,
                 row=row_num) for col_num in range(self.cols)])

That's rather gnarly code. If you're going to do that, it's probably
nice to use a temporary variable to clarify your intention:

         for row_num in range(self.rows):
             row = [GameTile(
                    value=random.choice([5, 6, 11,19, 20]), col=col_num,
                    row=row_num) for col_num in range(self.cols)
                    ]
             self.grid.append(row)


Which is still pretty gnarly. You only have three arguments to GameTile,
why do you need to use keyword arguments? This is neater and less
noisy, although it does require you get the order right:

I don't need them. Just hadn't settled on the order of them. But I will eliminate the requirement for the keyword arguments.

         # untested
         for row_num in range(self.rows):
             row = [GameTile(row_num, col_num, random.choice([5, 6, 11,19, 20])
                    for col_num in range(self.cols)
                    ]
             self.grid.append(row)

Even better:

         for row_num in range(self.rows):
             self.make_row(row_num)

     def make_row(self, row_num):
         values = self.allowed_values   # [5, 6, 11,19, 20]
         row = [GameTile(row_num, col_num, random.choice(values)
                for col_num in range(self.cols)]
         self.grid.append(row)


Notice that the values are stored in an attribute, for ease of
maintanence in the future when you extend them.

Much better. I think I need to do better at breaking down the given tasks to their smallest chunks to best take advantage of functions.

     def find_eliminations(self):
         # I define 3 variables for holding the 3 nodes/tiles that I am
         # currently checking to see if an elimination possibility exists.
         # It uses a math trick to check for elimination by adding the values
         # and checking for specific totals. None of the possible totals 
overlap.

Sorry, I'm too tired to make sense of this function right now :-(


     def check_total_and_eliminate(self, first, second, third):
         total = None
         if first.value == second.value:
             total = first.value + second.value + third.value
         elif second.value == third.value:
             total = first.value + second.value + third.value
         if total == 17 or total == 21 or total == 28 or total == 29 or \
             total == 31 or total == 42 or total == 45 or total == 46 \
             or total == 49 or total == 58:
             first.eliminated = True
             second.eliminated = True
             third.eliminated = True

I think this method does too much. I would prefer to see it split into
two methods, one to check the total, and the other to eliminate the
cells if needed:

     def eliminate(self, first, second, third):
         first.eliminated = True
         second.eliminated = True
         third.eliminated = True

     def check_total(self, first, second, third):
         if first.value == second.value or second.value == third.value:
             total = first.value + second.value + third.value
         return total in (17, 21, 28, 29, 31, 42, 45, 46, 49, 58)


which you then use:

      if self.check_total(first, second, third):
          self.eliminate(first, second, third)

Yes, another example of me trying to have my functions do too much. Thanks I will break it up.

Thanks again for the help, it should teach me to write better code in the future.
_______________________________________________
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor

Reply via email to