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