0

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.

JoeP
  • 45
  • 8
  • In your second elif statement you never check whether the number and `result[first_element]` are equal so they wil always add two numbers together. Thus giving 8 + 16 = 24 and then moving on to the next element. – Casper Kuethe Mar 10 '23 at 21:31
  • The logic seems flawed. The logic for 2048 is done in three steps: move all numbers in a tile to the direction (e.g. left), merge adjacent equal values starting from the outer edge (in our case from the left), and move again. – B Remmelzwaal Mar 10 '23 at 21:37

2 Answers2

1

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.

naffetS
  • 3,087
  • 2
  • 14
  • 24
  • Works great and is clearly efficient but is there any way to modify my code for it to work, I understand there are multiple ways to solve this problem. Such as what @Casper Kuethe mentioned, I had added a condition to the second elif to check if result[first_element] and number are the same but just get [16,0,0,0] for the last case. – JoeP Mar 10 '23 at 22:08
  • 1
    @JoeP [Here](http://tpcg.io/_8H06NB). There were a few bugs so I made a few changes, but hopefully you still understand it. Let me know if I need to clarify anything. – naffetS Mar 10 '23 at 22:43
  • Thanks so much I think I was overcomplicating it, cheers. – JoeP Mar 11 '23 at 12:50
1
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
Dimitrije
  • 11
  • 3
  • As it’s currently written, your answer is unclear. Please [edit] to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Mar 12 '23 at 23:50