On 01/02/2015 09:00 PM, 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. 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.
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.
2 "5"s followed or proceeded by an "11" will eliminate all 3 nodes.
2 "6"s followed or proceeded by a "5" will eliminate all 3 nodes.
2 "6"s followed or proceeded by a "19" will eliminate all 3 nodes.
2 "11"s followed or proceeded by a "6" will eliminate all 3 nodes.
2 "11"s followed or proceeded by a "20" will eliminate all 3 nodes.
2 "19"s followed or proceeded by a "20" will eliminate all 3 nodes.
2 "19"s followed or proceeded by an "11" will eliminate all 3 nodes.
2 "20"s followed or proceeded by a "6" will eliminate all 3 nodes.
2 "20"s followed or proceeded by a "5" will eliminate all 3 nodes.

The main focus of the code is the find_eliminations method. I think its
implementation is smart since it uses a math trick, but then again I
wrote it.
My math trick works by first finding 2 matching nodes next to each other
out of every 3 nodes, then adding the values of all 3 nodes together and
checking for specific totals. None of the possible totals overlap.

Here is the code:

import random


class GameTile():
     def __init__(self, value, col, row, **kwargs):
         # id is grid (X,Y) which is equal to grid (col,row)
         self.id = str(col) + ',' + str(row)
         self.col = col
         self.row = row
         self.value = value
         self.eliminated = False

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


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)])

     def print_by_col(self):
         # As in going down the column assuming we started at the top.
         for col_num in range(self.cols):
             for row_list in self.grid:
                 print(row_list[col_num])

     def print_by_row(self):
         # As in going right across the row assuming we started at the
left.
         for row in self.grid:
             for node in row:
                 print(node)

     def check_bounds(self, x, y):
         return (0 <= x < self.rows) and (0 <= y < self.cols)

     def lookup_node(self, x, y):
         if not self.check_bounds(x, y):
             return False
         return self.grid[x][y]

     def draw(self):
         for col in self.grid:
             print(end='| ')
             for node in col:
                 print(node, end=' | ')
             print()

     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.
         #First Down the columns.
         for col_num in range(self.cols):
             first = None
             second = None
             third = None
             for row_list in self.grid:
                 if row_list[col_num].row == 0:
                     first = row_list[col_num]
                 elif row_list[col_num].row == 1:
                     second = row_list[col_num]
                 elif row_list[col_num].row == 2:
                     third = row_list[col_num]
                 else:
                     first = second
                     second = third
                     third = row_list[col_num]

This code is way too complex for what it accomplishes. See  below.

                 if third is not None:
                     self.check_total_and_eliminate(first, second, third)
         # Now across the rows.
         for row in self.grid:
             first = None
             second = None
             third = None
             for node in row:
                 if node.col == 0:
                     first = node
                 elif node.col == 1:
                     second = node
                 elif node.col == 2:
                     third = node
                 else:
                     first = second
                     second = third
                     third = node

If the self.rows is 3, this is equivalent to just:
               first, second, third = row
If the self.rows is larger, it's equivalent to:
               first, second, third = row[p: p+3]  for some value of p

                 if third is not None:
                     self.check_total_and_eliminate(first, second, third)

But even better, let the method check_total_and_eliminate take a slice as its argument.
                  self.check-total_and_eliminate(row[p: p+3])

         # Set all eliminated nodes to a value of 0.
         for col in self.grid:
             for node in col:
                 if node.eliminated is True:
                     node.eliminated = False
                     node.value = 0

     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


This doesn't come close to implementing the test you describe above. For example, a total of 29 could be your first case, 5,5,19. But it could also be 4,4,21. Or 6,6,17. Etc.

I suggest instead that you compare the values against a table of interesting values. If you make your table a list of 3-tuples, it can be searched simply by:
      if tuple(nodes) in table:
            do-something

So you don't need the separate variables first, second, and third at all.



grid = GameGrid(4, 8)
grid.draw()
grid.find_eliminations()
print('After Eliminations')
grid.draw()


# END CODE

After this part has been improved, I then need to search the columns
backwards to be able to drop any floating values. Any none zero values
should not have a zero value below it. That is what I mean by drop
floating values. I think this will be simple by just using range method
to count backwards. I will be working on coding that in the meantime.


for what you've described so far, it might be convenient to store the board and its transposed equivalent. Then search the one for columns, and the other for rows. That's a later optimization, but it might save time getting the more complicated parts figured out.



--
DaveA
_______________________________________________
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor

Reply via email to