将微型列表附加到较大列表

3
我正在创建一个Python应用程序来玩Perudo游戏(或Liar's dice)。
我正在尝试创建一个函数,计算玩家(或AI)允许进行的所有可能移动,并返回它们的列表,以便可以拒绝非法移动。
回合被存储为2个数字的列表,例如[10,6]表示十个六。 如果起始变量currentbid是[19,3](十九个三),并且有20个骰子在游戏中,则唯一可能的移动是19个四,19个五,19个六,20个二,20个三,20个四,20个五和20个六。不允许叫做“一”。 程序应该输出上述内容:
[[19,4],[19,5],[19,6],[20,2],[20,3],[20,4],[20,5],[20,6]]

但是它会将其输出为:
[[20,6],[20,6],[20,6],[20,6],[20,6],[20,6],[20,6],[20,6]]

我做错了什么?

def calcpossiblemoves(self, currentbid, totalnoofdice):
    self.possiblemoves = []  # Create a list of possible moves that will be added too

    self.bid = currentbid

    while self.bid[0] <= totalnoofdice:

        while self.bid[1] < 6:
            self.bid[1] += 1
            self.possiblemoves.append(self.bid)     # <- I think the problem is something to do with this line
            print(self.possiblemoves) #For tracking the process

        # Increase 1st number, reset 2nd number to 1

        self.bid[0] += 1
        self.bid[1] = 1 # Which will get increased to 2
        #print("Reached 6")
    return self.possiblemoves

嗯...听起来有点像骗子骰子或Perudo,但没有1是特殊的... - Jon Clements
@JonClements 是的,我已经在帖子中写了那个,但它似乎消失了!现在重新加上去了。1s很特别,但我还没有加进去:P现在它们只是不可调用的。 - Tom Burrows
4个回答

1

在这里,最好考虑一个六进制数字,你可以有效地拥有20个骰子的数字范围为0-126。

current_bid = [19, 3]
offset = current_bid[0] * 6 + current_bid[1]
# 117 - and divmod(117, 6) == (19, 3)

因此,要获得剩下的有效出价,您需要在117-126的范围内进行计算,并获取有效的骰子数量和余数。
valid_bids_with1s = ([n // 6, n % 6 + 1] for n in range(offset, 126))
valid_bids = [[a, b] for a, b in valid_bids_with1s if b != 1]

这将给你:

[[19, 4],
 [19, 5],
 [19, 6],
 [20, 2],
 [20, 3],
 [20, 4],
 [20, 5],
 [20, 6]]

1
问题在于您正在使用可变对象——list,并且您正在创建引用而非副本。您可以通过每次复制self.bid列表来修复它,但最“pythonic”的解决方案是不使用list,而是使用tuple代替:
def calcpossiblemoves(self, currentbid, totalnoofdice):
    possiblemoves = []

    numberof, value = currentbid

    while numberOf <= totalnoofdice:

        while value < 6:
            value += 1
            possiblemoves.append((numberOf, value))

        # Increase 1st number, reset 2nd number to 1

        numberof += 1
        value = 1 # Which will get increased to 2
        #print("Reached 6")
    return self.possiblemoves

请注意,这不会更新self.bid(但您可以轻松添加),并且您将获得一个不可变的tuple列表。 编辑:因为tuple是不可变的,我使用了元组解包来创建两个变量。这是为了防止以下问题:
>>> bid = (1, 2)
>>> bid[0] += 1
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment

我可以写成 bid = (bid[0]+1, bid[1]),但是使用两个变量更容易理解,我的看法是这样的。


通常来说,确保列表(list)的所有成员意义相同是一个好的经验法则,而表示不同含义的值应该放在元组(tuple)、字典(dict)或自定义容器中,例如NamedTuple或自定义类。
在本例中,外部列表(list)包含多个出价,但每个内部列表(list)都有一定数量的骰子和一个值,这表明使用列表(list)可能是错误的类型。

谢谢,这似乎是最有帮助的答案。只是为了让我完全理解,如果我把 'possible moves.append((bid[0],bid[1]))' 放进去,它会起作用吗?我猜你只是为了清晰和强调图中的两个不同部分,按照你的经验法则(顺便说一下,这非常有帮助)。 - Tom Burrows

0

你正在将相同的对象附加到列表中,这就解释了为什么你会得到最后一个值6次。

替换

self.possiblemoves.append(self.bid)     # <- I think the problem is something to do with this line

self.possiblemoves.append(list(self.bid)) # make a copy of the list to make it independent from next modifications on self.bid

0
问题在于对self.bid的引用。 在列表中,它是同一个变量,这意味着当您在循环中更新它时,您正在更新每个实例(在本例中,列表中的所有变量)。 如果您想保持相同的格式,我已重写您要尝试的内容以按照您希望的方式工作,但正如其他人所说,您可以从编码的角度进行一些清理。
def calcpossiblemoves(currentbid, totalnoofdice):
    possiblemoves = []# in range(totalnoofdice)  #Create a list of possible moves that will be added too

    bid = currentbid
    available_bid = None

    while bid[0] <= totalnoofdice:

        while bid[1] < 6:
            bid[1] += 1
            available_bid = [bid[0],bid[1]]
            possiblemoves.append(available_bid)     # <- I think the problem is something to do with this line
            print(possiblemoves) #For tracking the process

        # Increase 1st number, reset 2nd number to 1

        bid[0] += 1
        bid[1] = 1 # Which will get increased to 2
        #print("Reached 6")
    return possiblemoves

calcpossiblemoves([19,3],20)

但是为什么 'available_bid' 不只是对 'bid' 的引用呢?这是 'available_bid = bid' 和 'available_bid = [bid[0],bid[1]]' 之间的区别吗?它们有什么不同? - Tom Burrows
我相当确定这与关键字“self”有关。这份文档很好地解释了“self”关键字:https://pythontips.com/2013/08/07/the-self-variable-in-python-explained/ 基本上,self关键字是指类或方法中变量的一个实例,对吧?所以,如果您正在运行此方法并不断访问self.variable,则正在访问单个实例,而不是创建变量的新实例。 - Michael Platt

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接