Repetitive For Loops in 2048 Game I have the following function defined in a program that implements the 2048 game. I tried condensing the repeating part of the code into one loop containing +1 offset variables for the indices, which are either set to 0 or 1 depending on the direction passed into the function, but the outer and inner loop variables swap depending on the direction. Could anyone give me some pointers as to how to condense this code and make it more clean, pythonic and terse?

def merge(direction):
    #if adjacent cells are equal, they are merged into one with twice the value and then moved.
    if direction == "up":
        for col in range(nColumns):
            for row in range(nRows-1):
                if grid[row][col] == grid[row+1][col]:
                    grid[row][col] = grid[row+1][col]*2
                    grid[row+1][col] = 0
                    move(direction)

    if direction == "down":
        for col in range(nColumns):
            for row in range(nRows-1):
                if grid[row][col] == grid[row+1][col]:
                    grid[row+1][col] = grid[row][col]*2
                    grid[row][col] = 0
                    move(direction)

    if direction == "left":
        for row in range(nRows):
            for col in range(nColumns-1):
                if grid[row][col] == grid[row][col+1]:
                    grid[row][col] = grid[row][col]*2
                    grid[row][col+1] = 0
                    move(direction)

    if direction == "right":
        for row in range(nRows):
            for col in range(nColumns-1):
                if grid[row][col] == grid[row][col+1]:
                    grid[row][col+1] = grid[row][col]*2
                    grid[row][col] = 0
                    move(direction)
Iterating more smartly can simplify your loops.

To start with, run this standalone example and see that the izip(…) expression produces useful pairs of coordinates:

from itertools import product, izip
nRows, nColumns = 3, 5
for dest, src in izip(product(range(nRows - 1), range(nColumns)),
                      product(range(1, nRows), range(nColumns))):
    print(dest, src)


Then, you can reuse the loop just by changing which ranges you pass in.

from itertools import product, izip

def merge(direction):
    def merge(dest_iterator, src_iterator):
        for (dr, dc), (sr, sc) in izip(dest_iterator, src_iterator):
            if grid[dr][dc] == grid[sr][sc]:
                 grid[dr][dc] == 2 * grid[sr][sc]
                 grid[sr][sc] = 0
                 move(direction)

    if direction == "up":
        merge(product(range(nRows - 1), range(nColumns)),
              product(range(1, nRows), range(nColumns)))
    elif direction == "down":
        merge(product(range(1, nRows), range(nColumns)),
              product(range(nRows - 1), range(nColumns)))
    elif direction == "left":
        merge(product(range(nRows), range(nColumns - 1)),
              product(range(nRows), range(1, nColumns)))
    elif direction == "down":
        merge(product(range(nRows), range(1, nColumns)),
              product(range(nRows), range(nColumns - 1)))