Making a shift function in 2048

2020-03-24 06:03发布

Let us say i have a list:

board = [2, 4, 0, 2, 8, 4, 4, 8, 0, 2, 0, 0, 4, 0, 2, 2]

and i already have some code that will make the list be displayed like this:

2 4 0 2
8 4 4 8
0 2 0 0
4 0 2 2

So is there a way for me to remove every 0 from each row and add it back in the end(even if there are different values in the list) so that the board now looks like:

2 4 2 0
8 4 4 8
2 0 0 0
4 2 2 0

I want to do this using a loop and not individually having to write separate code for each row.

Also can you do this without making the initial list to

board = [[2, 4, 0, 2], [8, 4, 4, 8], [0, 2, 0, 0], [4, 0, 2, 2]]

The code for 1 row would be :

board = [2, 0, 0, 2]
k = len(board)
board[:] = (value for value in board if value != 0)
while len(board) < k:
    board.append(0)
print(board)

Output = [2, 2, 0, 0]

3条回答
戒情不戒烟
2楼-- · 2020-03-24 06:16

Just for fun, here's a one-liner using some of Python's functional tools. The key ingredients are functools.partial, itertools.chain.from_iterable, and operator.not_, all of which come from the Functional Programming Modules section of Python's standard library documentation.

>>> import functools, itertools, operator
>>> board = [2, 4, 0, 2, 8, 4, 4, 8, 0, 2, 0, 0, 4, 0, 2, 2]
>>> list(itertools.chain.from_iterable(map(functools.partial(sorted, key=operator.not_), zip(*[iter(board)]*4))))
[2, 4, 2, 0, 8, 4, 4, 8, 2, 0, 0, 0, 4, 2, 2, 0]

Most of the work here is in turning the linear representation of the board into a nested list-of-lists representation, and then turning it back again. Here it is step-by-step.

First, turning the flat representation into a nested one:

>>> nested = list(zip(*[iter(board)]*4))
>>> nested
[(2, 4, 0, 2), (8, 4, 4, 8), (0, 2, 0, 0), (4, 0, 2, 2)]

I've added that extra outer list call just to show the contents of the zip iterable. It's not necessary once all the steps are put together. Now sort each row with a suitable key to move the zeros to the right:

>>> sorted_nested = list(map(functools.partial(sorted, key=operator.not_), nested))
>>> sorted_nested
[[2, 4, 2, 0], [8, 4, 4, 8], [2, 0, 0, 0], [4, 2, 2, 0]]

Again, the outer list call is unnecessary, and we'll lose it when we put everything together. A key point here is that Python's sorted function provides a stable sort, so the nonzero elements stay in the same order with respect to each other. Finally, flatten back into a list:

>>> list(itertools.chain.from_iterable(sorted_nested))
[2, 4, 2, 0, 8, 4, 4, 8, 2, 0, 0, 0, 4, 2, 2, 0]

Putting this all together, and removing the unnecessary inner conversions to list, you get the one liner at the top of this post.

>>> list(itertools.chain.from_iterable(map(functools.partial(sorted, key=operator.not_), zip(*[iter(board)]*4))))
[2, 4, 2, 0, 8, 4, 4, 8, 2, 0, 0, 0, 4, 2, 2, 0]
查看更多
beautiful°
3楼-- · 2020-03-24 06:27

Sometimes there is nothing wrong with a simple loop:

board = [2, 4, 0, 2, 8, 4, 4, 8, 0, 2, 0, 0, 4, 0, 2, 2]

x=4
nb=[]
for e in zip(*[iter(board)]*x):
    ne=[se for se in e if se!=0]
    nb.extend(ne+[0]*(x-len(ne)))  #.append if you want to maintain sub lists

>>> nb
[2, 4, 2, 0, 8, 4, 4, 8, 2, 0, 0, 0, 4, 2, 2, 0]
查看更多
疯言疯语
4楼-- · 2020-03-24 06:29

You can use list.count:

board = [2, 4, 0, 2, 8, 4, 4, 8, 0, 2, 0, 0, 4, 0, 2, 2]
new_board = [board[i:i+4] for i in range(0, len(board), 4)]
final_board = [list(filter(None, i))+([0]*i.count(0)) for i in new_board]
last_board = [i for b in final_board for i in b]

Output:

[2, 4, 2, 0, 8, 4, 4, 8, 2, 0, 0, 0, 4, 2, 2, 0]
查看更多
登录 后发表回答