"""
Clone of 2048 game.
"""
import poc_2048_gui
import random
# Directions, DO NOT MODIFY
UP = 1
DOWN = 2
LEFT = 3
RIGHT = 4
# Offsets for computing tile indices in each direction.
# DO NOT MODIFY this dictionary.
OFFSETS = {UP: (1, 0),
DOWN: (-1, 0),
LEFT: (0, 1),
RIGHT: (0, -1)}
def move_places(line, places):
"""
Helper function for merge.
Moves elements of places to first and second non-zero, or to end
of line. Can produce a zero if at end.
"""
while places[0] < len(line)-2 and line[places[0]] == 0:
places[0] += 1
places[1] = places[0] +1
while places[1] < len(line)-1 and line[places[1]] == 0:
places[1] += 1
return places
def merge(line):
"""
Helper function that merges a single row or column in 2048
"""
#copy input list
left_align = []
for dummy_index in range(len(line)):
left_align.append(line[dummy_index])
#list of two indexing parameters used to grab the next non-zero elements in list
places = [0,0]
#index value used to iterate through elements of list
index = 0
#bool used to check whether the places have reached end of list
#if true, need to account for special cases, i.e. non-zeros
end = False
#iterate over list
while index < len(left_align)-1:
#print "Iteration " + str(index)
#print "List: " + str(left_align)
#places returned to index, index+1, then sent to find non-zeros
places[0] = index
places[1] = index
move_places(left_align, places)
#print "index:" + str(index) + "; P1:" + str(places[0]) + "; P2:" + str(places[1])
#check if places
end = places[0] == len(left_align) - 2
#check if selected elements in list are a match
if left_align[places[0]] == left_align[places[1]]:
#print "match"
#place combined values into current index location & set prevous values to 0
left_align[index] = 2 * left_align[places[0]]
if index != places[0]:
left_align[places[0]] = 0
left_align[places[1]] = 0
#print result and return result if at end
#print left_align
if end:
#print "at end"
return left_align
#logic for non-matching selected values
else:
#print "no match"
#move first value to list[index] and delete from previous location
left_align[index] = left_align[places[0]]
if index != places[0]:
left_align[places[0]] = 0
if end:
#print "at end"
#cases: [I,P0 = 0,P1] or [I = P0 = 0,P1]
#excpetion: index will become 0, so must move P1 to index
if left_align[index] == 0:
#print "places1 was zero. Moving places2 to index"
left_align[index] = left_align[places[1]]
#delete P1. moved to index, so no need for conditional check
left_align[places[1]] = 0
#cases: [I,P1,P2], [I,P1,0], [I/P1, P2], [I/P1, 0], [0,P2]
#exception: whether P1 is 0 or not, move to index+1 before returning list
else:
left_align[index + 1] = left_align[places[1]]
if (index + 1) != places[1]:
left_align[places[1]] = 0
return left_align
#print left_align
#print "-------------------------------"
index += 1
return left_align
class TwentyFortyEight:
"""
Class to run the game logic.
"""
def __init__(self, grid_height, grid_width):
self._rows = grid_height
self._columns = grid_width
self._grid = []
self._borders = {UP: [(0,col)for col in range(self._columns)] ,
DOWN: [(self._rows-1,col)for col in range(self._columns)],
LEFT: [(row,0)for row in range(self._rows)],
RIGHT: [(row,self._columns-1)for row in range(self._rows)]}
self.reset()
def reset(self):
"""
Reset the game so the grid is empty except for two
initial tiles.
"""
#create grid of variable size filled with values of 0
self._grid = [[0 for dummy_w in range(self._columns)] for dummy_h in range(self._rows)]
#generate initial values for playing in GUI
self.new_tile()
self.new_tile()
self.new_tile()
self.new_tile()
self.new_tile()
self.new_tile()
def __str__(self):
"""
Return a string representation of the grid for debugging.
"""
print "Rows of Grid:"
for row_num in range(self._rows):
print self._grid[row_num]
return str(self._grid)
def get_grid_height(self):
"""
Get the height of the board.
"""
return self._rows
def get_grid_width(self):
"""
Get the width of the board.
"""
return self._columns
def get_merge_list(self, cell, direction, num_steps):
merged_list = []
for step in range(num_steps):
row = cell[0] + OFFSETS[direction][0] * step
col = cell[1] + OFFSETS[direction][1] * step
merged_list.append(self._grid[row][col])
return merged_list
def store_values(self, cell, values, direction, num_steps):
for step in range(num_steps):
row = cell[0] + OFFSETS[direction][0] * step
col = cell[1] + OFFSETS[direction][1] * step
self._grid[row][col] = values.pop(0)
def move(self, direction):
"""
Move all tiles in the given direction and add
a new tile if any tiles moved.
"""
moved = False
for tile in self._borders[direction]:
#gives either the #rows if up/down or #columns if right/left
steps = abs(OFFSETS[direction][0] * self._rows + OFFSETS[direction][1] * self._columns)
merge_list = self.get_merge_list(tile, direction, steps)
value_list = merge(merge_list)
if value_list != merge_list:
moved = True
self.store_values(tile, value_list, direction, steps)
#only add new tile if the pieces moved (i.e. there were open spaces to slide tiles)
if moved:
self.new_tile()
def new_tile(self):
"""
Create a new tile in a randomly selected empty
square. The tile should be 2 90% of the time and
4 10% of the time.
"""
new_values = [2,2,2,2,2,2,2,2,2,4]
value_placed = False
full = False
full_row = 0
for row_check in self._grid:
if 0 not in row_check:
full_row += 1
if full_row >= self._rows:
print "full"
full = True
while not value_placed and not full:
row = random.randint(0,self._rows -1)
col = random.randint(0,self._columns -1)
if self._grid[row][col] == 0:
self._grid[row][col] = random.choice(new_values)
value_placed = True
#print "Placing " + str(self.grid[row][col]) + " in row " + str(row) + " column " + str(col)
def set_tile(self, row, col, value):
"""
Set the tile at position row, col to have the given value.
"""
self._grid[row][col] = value
def get_tile(self, row, col):
"""
Return the value of the tile at position row, col.
"""
# replace with your code
return self._grid[row][col]
poc_2048_gui.run_gui(TwentyFortyEight(4, 4))
Comments