2014-08-28 80 views
0

我试图做一个函数,它在2048板(嵌套列表制作4×4格),这样,所有可能的随机瓷砖

[[0, 2, 2, 2], 
[2, 2, 2, 2], 
[2, 2, 2, 2], 
[2, 2, 2, 2]] 

注:我知道这是不是一个现实的2048板,但我选择了简单

的例子和功能应该输出所有的地方的名单随机瓷砖可能出现(或者是2或4)

例如,如果我在上面的板上运行该功能,输出应该是。

[[[2, 2, 2, 2], 
    [2, 2, 2, 2], 
    [2, 2, 2, 2], 
    [2, 2, 2, 2]], 

[[4, 2, 2, 2], 
    [2, 2, 2, 2], 
    [2, 2, 2, 2], 
    [2, 2, 2, 2]]] 

所以在任何地方都存在一个0,我们想使一个板哪里有0已经被替换为2和其他地方已经换成了4

这里是我的代码,以便远。

def all_rand_tiles(state): 
    states = [] 
    changed = [] 
    old_states = [None] 
    while old_states != states: 
     old_states = states 
     new_state = state 
     for row in range(4): 
      for tile in range(4): 
       if state[row][tile] == 0: 

        #AREA WITH PROBLEM BELOW THIS LINE 
        if [row, tile] not in changed: 
         new_state[row][tile] = 2 
         states.append(new_state) 

         new_state[row][tile] = 4 
         states.append(new_state) 
         changed.append([row, tile]) 

    return states 

的问题是,当我if语句追加两种不同的状态在最后,这两个州有零变为4.因此函数的输出,如果你在上面板上运行看起来像这样。

[[[4, 2, 2, 2], 
    [2, 2, 2, 2], 
    [2, 2, 2, 2], 
    [2, 2, 2, 2]], 

[[4, 2, 2, 2], 
    [2, 2, 2, 2], 
    [2, 2, 2, 2], 
    [2, 2, 2, 2]]] 

当我运行new_state[row][tile] = 4我刚刚创建的状态改变为它有2,有4

你可以看到问题的证明,如果你之前和运行new_state[row][tile] = 4后打印new_state糟糕的代码区域。

我非常困惑,我不知道为什么我有这个愚蠢的问题。

编辑:请在发布之前试用您的解决方案。我已向您提供了我正在使用all_rand_tiles的唯一功能,到目前为止,我一直无法解决已提交的任何答案的问题。

+0

@jonrsharpe请详细说明。 – 2014-08-28 19:50:14

+0

简短的回答可能是“参照平等”。作为一个简单的例子,'a = []; b = a;在b.append(23);打印一个'会打印'[23]',即使你在创建后没有对'a'进行任何明显的修改。 – Kevin 2014-08-28 19:50:27

+0

你正在更换'0'的这块主板是在你刷卡后马上发生的,对吧? – TheSoundDefense 2014-08-28 19:51:58

回答

2

必须创建state一个拷贝,并用new_state设置。因为你有一个2D array您必须使用deepcopy使你的代码改成这样:

from copy import deepcopy 


state=[[0, 0, 2, 2], 
    [2, 2, 2, 2], 
    [2, 2, 2, 2], 
    [2, 2, 2, 2]] 

def all_rand_tiles(state): 
    states = [] 
    changed = [] 
    old_states = [None] 
    while old_states != states: 
     old_states = states 
     new_state = deepcopy(state) 
     for row in range(4): 
      for tile in range(4): 
       if state[row][tile] == 0: 

        if [row, tile] not in changed: 
         new_state[row][tile] = 2 
         states.append(new_state) 
         new_state = deepcopy(state) 

         new_state[row][tile] = 4 
         states.append(new_state) 
         new_state = deepcopy(state) 
         changed.append([row, tile]) 

    return states 

print all_rand_tiles(state) 

DEMO:

[[[2, 0, 2, 2], 
[2, 2, 2, 2], 
[2, 2, 2, 2], 
[2, 2, 2, 2]], 

[[4, 0, 2, 2], 
[2, 2, 2, 2], 
[2, 2, 2, 2], 
[2, 2, 2, 2]], 

[[0, 2, 2, 2], 
[2, 2, 2, 2], 
[2, 2, 2, 2], 
[2, 2, 2, 2]] 

[[0, 4, 2, 2], 
[2, 2, 2, 2], 
[2, 2, 2, 2], 
[2, 2, 2, 2]]] 
+0

太棒了!这是我刚刚给出的非常长的解释的一个更简单的版本。 (我希望我们都能得票。) – BrettFromLA 2014-08-28 19:56:15

+0

我修改了代码以使用这个复制功能,但问题依然存在。如果你不相信我,你可以在这里运行代码。 http://labs.codecademy.com/ – 2014-08-28 20:01:56

+0

因为我没有完整的代码,我不能尝试任何事情。 – Kasramvd 2014-08-28 20:19:26

2

的问题是,当你调用states.append(new_state)要附加一个参考到NEW_STATE到列表中,而不是一个复制。因此,对new_state对象所做的任何修改都会影响对它的所有引用。为了获得你想要的行为,你需要对新状态进行修改,然后将该状态的副本附加到new_states对象。有几种方法可以做到这一点:

states.append(new_state[:]) # slice the list 
states.append(copy.copy(new_state)) # use the copy function 
states.append(list(new_state)) # explicitly construct a new list 
2

我不知道Python的具体,但我一直在编程大约20年所以我的回答可能是有道理的。你的阵列追加了两次,下面的代码:

if [row, tile] not in changed: 
    new_state[row][tile] = 2 
    states.append(new_state) <--- appended the first time here 

    new_state[row][tile] = 4 
    states.append(new_state) <--- appended the second time here 
    changed.append([row, tile]) 

难道追加NEW_STATE阵列本身,或者只是一个参考NEW_STATE阵列?如果它是对new_state数组的引用,那么这两个实例将是相同的,因为这两个引用都指的是new_state的最新版本(其在该行的&瓦片中具有“4”)。

如果这是原因,那么解决方案是在使用states.append之前,先对数组进行实际的复制/克隆,或者将new_state中的每个值单独复制到新数组中。

+0

作为一个不熟悉python的人,我很佩服你的回答! ;) – Kasramvd 2014-08-28 20:10:01

+0

谢谢@Kasra!我在其他语言中遇到了同样的问题,所以我认为它可能适用。 :) – BrettFromLA 2014-08-28 22:02:44

+0

我很高兴(Y)...! – Kasramvd 2014-08-28 22:31:53