在Prolog中,如何从一组52张卡片中随机选取2个值?即Player1(X,Y),X是52中的任何一张牌,Y是另一张牌,它们必须是不同的。Player2将得到同样的待遇,他的牌必须与已经选择的牌不同。谢谢。
发布于 2014-02-15 20:19:51
在SWI-Prolog中,我会做一个pick_card/3
pick_card(Cards, Card, Rest) :-
length(Cards, N), random_between(1, N, R), nth1(R, Cards, Card, Rest).
并应用它2次
pick_two_cards(Cards, C1,C2, Rest) :-
pick_card(Cards, C1, R1),
pick_card(R1, C2, Rest).
发布于 2014-02-15 21:28:39
基本上,任务是从集合1..52中抽取4个不同的元素。
例如,在Python中,有一个用于此操作的标准函数,代码为
random.sample(range(1, 52 + 1), 4)
我已经看过了Python是如何实现random.sample(range(1..N + 1), K)
的--它基本上就是K个生成随机数1..N的步骤,并且在每一步中,只要在当前生成的数已经在上一步中被选中的情况下继续尝试生成随机数即可。它看起来效率很低,但可能需要它来归档分布的一致性。
让我们为Prolog创建一个类似的(但简化的) sample
谓词。
sample(N, K, Sample) :-
sample(N, K, [], Sample).
sample(_, 0, _, []).
sample(N, K, Selected, [X | Rest]) :-
K > 0,
new_random_index(N, Selected, X),
NewSelected = [X | Selected],
NewK is K - 1,
sample(N, NewK, NewSelected, Rest).
new_random_index(N, Selected, X) :-
(
% Can be implementation-specific. Works in B-Prolog and ECLiPSe CLP.
X is (random mod N) + 1,
\+ membchk(X, Selected)
;
new_random_index(N, Selected, X)
).
几个测试运行:
| ?- sample(52, 4, Sample).
sample(52, 4, Sample).
Sample = [40,23,38,44] ?
yes
| ?- sample(52, 4, Sample).
sample(52, 4, Sample).
Sample = [2,28,39,17] ?
yes
如果将membchk
测试改为使用集合而不是列表来测试成员资格的谓词,则可以大大提高程序的效率。但这是非常特定于实现的。
发布于 2014-02-16 01:42:28
如果你想重复地抽出随机的牌,最好是一次洗完整个列表,然后简单地从前面挑选牌。一些Prologs (例如ECLiPSe)有一个库谓词,所以你可以直接调用
lists:shuffle(Cards, [Card1,Card2|Rest]).
如果你想自己写一个shuffling,这里有一个巧妙的技巧:
shuffle(Xs, Rs) :-
add_random_keys(Xs, KXs), % add random key to each list element
keysort(KXs, KRs), % sort by keys, perturbing original order
strip_keys(KRs, Rs). % remove the keys again
add_random_keys([], []).
add_random_keys([X|Xs], [K-X|KXs]) :-
random(K),
add_random_keys(Xs, KXs).
strip_keys([], []).
strip_keys([_K-X|KXs], [X|Xs]) :-
strip_keys(KXs, Xs).
https://stackoverflow.com/questions/21802746
复制相似问题