abbarnes icon

2048 game [codeskulptor]

abbarnes | PRO | 12/12/17 03:29:15 PM UTC | 0 ⭐ | 166 👁️ | Never ⏰ | []
Python |

8.04 KB

|

None

|

0 👍

/

0 👎

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