[Tutor] Improving My Simple Game Code for Speed, Memory and Learning

WolfRage wolfrage8765 at gmail.com
Fri Jan 2 23:35:23 CET 2015

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]
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 third is not None:
self.check_total_and_eliminate(first, second, third)
# 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

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.