英文:
random.sample producing same output when iterated over inside function
问题
我正在尝试编写一个带有蒙特卡洛模拟的扑克手牌评估器。
在模拟游戏结果(例如发牌)时,在使用random.sample
进行随机化的函数内部,随机化正常运作。
def simulate(hands, board):
# 创建牌堆
suits = ['d','s','c','h']
ranks = ['A','2','3','4','5','6','7','8','9','T','J','Q','K']
cards = []
for r in ranks:
for s in suits:
cards.append(r+s)
# 洗牌
deck = random.sample(cards, len(cards))
# 从牌堆中移除公共牌和玩家手牌
deck = list(filter(lambda x: x not in board, deck))
for hand in hands:
deck = list(filter(lambda x: x not in hand, deck))
# 发转牌和河牌
while len(board) < 5:
card = deck.pop(0)
board.append(card)
return board
for i in range(2):
outcome = simulate([['Ah', 'Ac'], ['7s', '6s']], ['2d', '5s', '8s'])
print(outcome)
输出:
['2d', '5s', '8s', '9s', 'Jc']
['2d', '5s', '8s', '4s', '3s']
如果我将这段代码放入另一个函数中,随机化会失效,我一直得到相同的结果。
def monte_carlo(hands, board, samples=5):
for i in range(samples):
outcome = simulate(hands, board)
print(outcome)
monte_carlo([['Ah', 'Ac'], ['7s', '6s']], ['2d', '5s', '8s'])
输出:
Board ['2d', '5s', '8s', '2c', '4d']
None
Board ['2d', '5s', '8s', '2c', '4d']
None
Board ['2d', '5s', '8s', '2c', '4d']
None
Board ['2d', '5s', '8s', '2c', '4d']
None
Board ['2d', '5s', '8s', '2c', '4d']
这种行为的原因是什么?
英文:
I'm trying to write a poker hand evaluator with a monte carlo simulation.
When simulating game outcomes (e.g. dealing cards) inside a function using random.sample
randomization works fine.
def simulate(hands, board):
# create deck
suits = ['d','s','c','h']
ranks = ['A','2','3','4','5','6','7','8','9','T','J','Q','K']
cards = []
for r in ranks:
for s in suits:
cards.append(r+s)
# shuffle deck
deck = random.sample(cards,len(cards))
# remove board and player cards from deck
deck = list(filter(lambda x: x not in board, deck))
for hand in hands:
deck = list(filter(lambda x: x not in hand, deck))
# deal turn and river
while len(board) < 5:
card = deck.pop(0)
board.append(card)
return board
for i in range(2):
outcome = simulate([['Ah', 'Ac'], ['7s', '6s']], ['2d', '5s', '8s'])
print(outcome)
Output:
['2d', '5s', '8s', '9s', 'Jc']
['2d', '5s', '8s', '4s', '3s']
If I run this inside a for loop it works fine but
once I put this into another function randomization fails and I keep getting the same result.
def monte_carlo(hands, board, samples=5):
for i in range(samples):
outcome = simulate(hands, board)
print(outcome)
monte_carlo([['Ah', 'Ac'], ['7s', '6s']], ['2d', '5s', '8s'])
Output:
Board ['2d', '5s', '8s', '2c', '4d']
None
Board ['2d', '5s', '8s', '2c', '4d']
None
Board ['2d', '5s', '8s', '2c', '4d']
None
Board ['2d', '5s', '8s', '2c', '4d']
None
Board ['2d', '5s', '8s', '2c', '4d']
What is the reason for this behaviour?
答案1
得分: 1
这是关于list
类型以及它是可变的一个棘手的问题。如果你将这行代码更改为:outcome = simulate(hands, [b for b in board])
,你将获得所期望的结果。
[b for b in board]
只是创建一个新的列表,其中包含与board
相同的元素。重要的是,在Python中,它在幕后实际上是一个不同的列表。它与新的内存相关联。如果不这样做,每次循环迭代中使用的board
都是对完全相同列表的引用。为了可视化它,将这个调试添加到代码中:
def monte_carlo(hands, board, samples=5):
print("现在我的板有值:", board)
for i in range(samples):
outcome = simulate(hands, board)
print(outcome)
你会看到这个调试在时间上显示了board
的值变化,尽管被打印出来的board
位于simulate
函数之外。因为列表是可变的,所有对列表的引用都指向完全相同的内存。这不是每次运行simulate(hands, board)
时都会发送一个全新版本的board
,就像你在调用monte_carlo(hands, board)
时一样。不,你实际上是在发送相同的列表。并且因为在simulate
内部你改变了列表(即添加元素),这些更改也存在于monte_carlo
方法对board
的引用中。
英文:
This is a tricky little piece around the list
type and the fact it's mutable. If you change this line of code: outcome = simulate(hands, board)
to outcome = simulate(hands, [b for b in board])
you'll get the desired result.
The [b for b in board]
just creates a new list which has the same elements as board
. Importantly, it is a different list behind the scenes in python. New memory is associated with it. If you don't do this, the board
that is being used in each iteration of the loop is a reference to the exact same list. To visualise it, add this debug into the code:
def monte_carlo(hands, board, samples=5):
print("NOW MY BOARD HAS VALUE: ", board)
for i in range(samples):
outcome = simulate(hands, board)
print(outcome)
You'll see that that debug shows the value of board
changing in time, even though the board
that's being printed is outside the simulate
function. Because lists are mutable, all references to the list point to the exact same memory. It's not like each time you run simulate(hands, board)
you're sending in a brand new version of board
, exactly as it was when you called monte_carlo(hands, board)
. No, you're sending in the exact same list. And because inside simulate
you're changing the list (i.e. adding elements), those changes also exist in the monte_carlo
method's reference to board
.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论