Reputation: 502
This is part of an online course homework where we are asked to build a merge function for the 2048 game. The function takes a list as an argument and iterate through it to return another list where the same elements are merged, and the list is updated.
So far I'm able to check for empty tiles "zeros" and return a list that has the rest of the numbers. Code:
def merge(line):
"""
A function that merges a single row or column in 2048.
"""
output = [0]* len(line)
output1 = [0]* len(line)
for num in line:
if num != 0:
output.insert(-1,num)
del output[0]
the next step where I am stuck is how to evaluate the new list to merge "sum" items that are of the same value.
I want to extend the function to something that does this:
for num in output:
if num == "the next item in list":
return the sum of both items and skip to the next item
output1.insert(-1, "the sum of the two items")
del output1[0]
we were provided with tests to run to see if our code is functioning properly
[2, 0, 2, 4] should return [4, 4, 0, 0],
[0, 0, 2, 2] should return [4, 0, 0, 0],
[2, 2, 0, 0] should return [4, 0, 0, 0],
[2, 2, 2, 2, 2] should return [4, 4, 2, 0, 0],
[8, 16, 16, 8] should return [8, 32, 8, 0]
your help is much appreciated
Upvotes: 2
Views: 261
Reputation: 564
This is how I attempted it: I remove all 0s, but I remember, how many there were. Then I go through the list, comparing always two items. If they are the same, then I save the sum and remember, that I do not want to regard the second one in the next step. If they are not the same, then I just add the value as it is. Finally, I look at the last value and add the missing 0s.
l = [8,16,16,8]
z = l.count(0)
l = [x for x in l if x!=0]
new = []
go_over = []
for i in range(len(l)-1):
if i in go_over:
continue
if l[i] == l[i+1]:
new.append(2*l[i])
go_over.append(i+1)
else:
new.append(l[i])
if len(l)-1 not in go_over:
new.append(l[-1])
new += [0]*(len(go_over)+z)
print(new)
Upvotes: 0
Reputation: 8510
I also did it with groupby
and also the grouper
recipe
from itertools import groupby, izip_longest, ifilter, repeat
def grouper(iterable, n, fillvalue=None):
"Collect data into fixed-length chunks or blocks"
# grouper('ABCDEFG', 3, 'x') --> ABC DEF Gxx
args = [iter(iterable)] * n
return izip_longest(fillvalue=fillvalue, *args)
def merge(line):
size = len(line)
resul = []
for num,val in groupby(ifilter(bool,line)):
for pair in grouper(val,2,0):
resul.append( sum(pair) )
if len(resul) < size:
resul.extend( repeat(0,size-len(resul)) )
return resul
first with ifilter
I eliminate the 0, then gruopby
give me the numbers in, well, groups of the same number, and with grouper
I build pair with those that I sum and append to the result. Finally I append the missing 0 to the end with the extend method if needed
Upvotes: 0
Reputation: 37529
I did it in two steps, too. Move all the numbers left, removing any zeros. Then iterate through the list of numbers combining 2 like numbers. I used itertools.groupby to make the iterating through like numbers easier.
groupby
returns an iterator for each group of like numbers so:
[2,2,0,0]
becomes
[(2, [2, 2]), (0, [0, 0])]
It makes it easier to process each similar group as a separate chunk.
For groups of similar numbers like [2,2]
or [2,2,2]
, the output will always be a list of half the length and the items in the list will all be 2*n
(for odd length lists, there is an extra last element that will just be n
).
from itertools import groupby
def merge(line):
cnt = len(line)
# Move all numbers left, removing zeros
line = [num for num in line if num != 0]
out = []
# Combine like numbers
for num, niter in groupby(line):
ncnt = len(list(niter))
out.extend([num * 2] * (ncnt // 2))
if ncnt % 2:
out.append(num)
# Right pad the list with zeros to the original line length
out.extend([0] * (cnt - len(out)))
return out
Upvotes: 1