我已经列出了一个看起来像2048板的列表:
nlist = [2, 2, 4, 8, 0, 2, 8, 0, 0, 0, 0, 2, 4, 2, 2, 0]
在2048游戏板上看起来像这样:
2 2 4 8
0 2 8 0
0 0 0 2
4 2 2 0
我想进行移位,将每个列(不是行)中的所有0都删除,然后放回去,以便0处于底部,非零数字转到顶部,这样当我按 w 键时,该面板现在看起来像这样:
2 2 4 8
4 2 8 2
0 2 2 0
0 0 0 0
我只需要找到一种方法来遍历每行和每行有2个for循环。
答案 0 :(得分:4)
如果您使用2D NumPy数组,或者至少使用行列表列表或列列表列表,而不是像这样的平面列表,这会容易得多。
但是,如果您想使用平面列表,可以通过添加按行和列访问该列表的函数来简化操作,因此您不必到处都写算法:
def getrc(nlist, width, r, c):
return nlist[r*width+c]
def setrc(nlist, width, r, c, value):
nlist[r*width+c] = value
现在,获取或设置整个列很简单:
def getc(nlist, size, c):
return [getrc(nlist, size, r, c) for r in range(size)]
def setc(nlist, size, c, col):
for r in range(size):
setrc(nlist, size, r, c, col[r])
现在您只需要编写一个带有列列表的shift
函数:
def shift(lst):
# Get all the nonzero values in the column
result = [value for value in lst if value]
# And pad it with zeros
result.extend(0 for value in lst if not value)
return result
现在您可以将它们放在一起:
def shiftcolumns(nlist, size):
for c in range(size):
col = getc(nlist, size, c)
col = shift(col)
setc(nlist, size, c, col)
您能使它更简洁或更有效吗?当然。但是您能够理解,调试和扩展代码吗?如果没有,则保持简单。
如果您真的希望它更高效-尽管几乎没有关系-您可能应该在这里使用NumPy。
如果您真的希望它简洁明了,您应该再次 在此处使用NumPy。然后,代码不仅会更短,而且更容易理解,更难出错。 (或者,如果您这样做是为了练习如何教自己如何进行2D索引,请编写您的 own 2D数组类,该类只包含NumPy所做的一小部分,将这些{{1 }},getrc
,setrc
等在getc
和__getitem__
方法中起作用。)
答案 1 :(得分:2)
一种简单的方法是使用读写循环
for col in range(4):
wp = 0 # write pointer
for row in range(4): # read loop
if data[row*4+col] != 0:
# non-zero: copy this element in place
data[wp*4+col] = data[row*4+col]
wp += 1
# Fill the rest with zeros
for row in range(wp, 4):
data[row*4+col] = 0
答案 2 :(得分:1)
import operator
nlist = [2, 2, 4, 8, 0, 2, 8, 0, 0, 0, 0, 2, 4, 2, 2, 0]
size = int(len(nlist) ** .5)
print(list(zip(*map(lambda c: list(filter(bool, c)) + list(filter(operator.__not__, c)), zip(*[nlist[i * size: (i + 1) * size] for i in range(size)])))))
这将输出:
[(2, 2, 4, 8), (4, 2, 8, 2), (0, 2, 2, 0), (0, 0, 0, 0)]
或者如果您希望将其展平:
print([a for r in zip(*map(lambda c: list(filter(bool, c)) + list(filter(operator.__not__, c)), zip(*[nlist[i * size: (i + 1) * size] for i in range(size)]))) for a in r])
这将输出:
[2, 2, 4, 8, 4, 2, 8, 2, 0, 2, 2, 0, 0, 0, 0, 0]
答案 3 :(得分:1)
我对这个问题的看法:
from itertools import chain
nlist = [2, 2, 4, 8, 0, 2, 8, 0, 0, 0, 0, 2, 4, 2, 2, 0]
def slice(l):
for i in range(4):
new_row = []
for j in nlist[i::4]:
try:
new_row.insert(new_row.index(0), j) if j > 0 else new_row.append(j)
except ValueError:
new_row.insert(1, j)
yield new_row
new_list = list(chain.from_iterable(zip(*slice(nlist))))
for i in range(4):
print(nlist[i*4:i*4+4])
print()
for i in range(4):
print(new_list[i*4:i*4+4])
print(f'\nnew_list={new_list}')
输出为:
[2, 2, 4, 8]
[0, 2, 8, 0]
[0, 0, 0, 2]
[4, 2, 2, 0]
[2, 2, 4, 8]
[4, 2, 8, 2]
[0, 2, 2, 0]
[0, 0, 0, 0]
new_list=[2, 2, 4, 8, 4, 2, 8, 2, 0, 2, 2, 0, 0, 0, 0, 0]
答案 4 :(得分:1)
这是您想要做的另一种方式。注意,为了测试目的,我稍微修改了板子数据。
def vert_shift_zeros(board, width, height):
""" Shift all the zeros to the end of each column in the board. """
for col in range(width):
# Get a column of data.
column = [board[row*width + col] for row in range(height)]
# Shift all the zeros in it to the end.
shifted_column = [value for value in column if value]
shifted_column.extend([0 for _ in range(height-len(shifted_column))])
# Replace column with shifted data.
for row in range(HEIGHT):
board[row*width + col] = shifted_column[row]
if __name__ == '__main__':
# A non-square board for testing purposes.
WIDTH, HEIGHT = 5, 4
nlist = [2, 2, 4, 8, -1,
0, 2, 8, 0, -2,
0, 0, 0, 2, -3,
4, 2, 2, 0, -4]
vert_shift_zeros(nlist, WIDTH, HEIGHT)
for row in range(HEIGHT):
print(', '.join(str(value)
for value in nlist[row*WIDTH: (row+1)*WIDTH]))
输出:
2, 2, 4, 8, -1
4, 2, 8, 2, -2
0, 2, 2, 0, -3
0, 0, 0, 0, -4