Repetitive For Loops in 2048 Game
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)))