2048 game on 1d list – why it works for some tests and not others?

Question:

Trying to implement the 2048 game in python, starting with a function that merges a 1d list . My code works for all but one test see below. I believe this is due to the code not processing consecutive duplicates but not sure of the best way to implement this, here is my code so far:

def merge(line):
    """
    Function that merges a single row or column in 2048.
    """
    
    tile_merged = False
    first_element = 0
    result = [0 for element in line]
    
    for number in list(line): 
        if tile_merged == False:
            if number != 0 and result[first_element] == 0:
                result[first_element] = number
                tile_merged = False
               
            elif number != 0 and result[first_element] > 0:
                result[first_element] += number
                tile_merged = True
                first_element += 1
            tile_merged = False       
    return result

print merge([2,0,2,4]) # [4,4,0,0]
print merge([0,0,2,2]) # [4,0,0,0]
print merge([2,2,0,0]) # [4,0,0,0]
print merge([2,2,2,2,2]) # [4,4,2,0,0]
print merge([8,16,16,8]) # [24,24,0,0] should be [8,32,8,0]

any help appreciated.

Asked By: JoeP

||

Answers:

I believe this function should do what you want:

def merge(l):
    # keeping track of the previous element
    prev = None
    res = []

    for item in l:
        # if it is zero, we ignore it to remove the empty space
        if item == 0:
            continue

        if item == prev:
            # they are the same, so let's merge.
            # we replace the last item with the merged version
            res[-1] += item

            # set prev to None again to prevent this one from being merged with the next
            prev = None

        else:
            # they are not the same, so we just append it unchanged and store this item in prev.
            res.append(item)
            prev = item

    # pad with zeros
    res.extend([0] * (len(l) - len(res)))

    return res

I tested it with your cases and it works.

This simply keeps track of the previous item, ignores the zeros, and if the current one is the same as the previous one, then they are merged.

Answered By: naffetS
def merge(line):
    """
    Function that merges a single row or column in 2048.
    """
    result = [0] * len(line)
    line = [x for x in line if x != 0]

    r = 0
    while line:
        first = line.pop(0)
        if line and first == line[0]:
            result[r] = 2 * first
            line.pop(0)
        else:
            result[r] = first

        r += 1
    
    return result

from parameterized import parameterized
from unittest import TestCase, main

class TestMerge(TestCase):
    @parameterized.expand([
        [[2,0,2,4], [4,4,0,0]],
        [[0,0,2,2], [4,0,0,0]],
        [[2,2,0,0], [4,0,0,0]],
        [[2,2,2,2,2], [4,4,2,0,0]],
        [[8,16,16,8], [8,32,8,0]],
    ])
    def test_merge(self, line, expected):
        calculated = merge(line)
        assert calculated == expected

main(argv=[''], verbosity=2, exit=False)

Would this work for your use case?

Output

test_merge_0 (__main__.TestMerge) ... ok
test_merge_1 (__main__.TestMerge) ... ok
test_merge_2 (__main__.TestMerge) ... ok
test_merge_3 (__main__.TestMerge) ... ok
test_merge_4 (__main__.TestMerge) ... ok

----------------------------------------------------------------------
Ran 5 tests in 0.003s

OK
Answered By: Dimitrije
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.