问题描述
对于以下数据类型,如何返回随机值?
datatype rank = Jack | Queen | King | Ace | Num of int
我正在研究一个函数,该函数会生成随机卡的列表以输入到另一个函数,因此也需要类似的函数来适合西装。
输出应为Jack,King等符号,或2到9之间的整数。
以下代码不正确:
fun pick_rank() =
case Random.randRange(2,13) of 13 => Ace
| 12 => King
| 11 => Queen
| 10 => Jacl
| Int v => v
解决方法
对于以下数据类型,如何返回随机值?
datatype rank = Jack | Queen | King | Ace | Num of int
我有两个答案:要么唯一地生成每个值,要么生成所有可能的值,将它们混洗并选择一个。如果只想隔离一个随机变量,则前者是最简单的。但是,如果您要模拟不能两次绘制同一张纸牌的纸牌游戏,那么您可能需要随机播放。
您可以看到我是如何制作command-line blackjack game的。在这里我将重复两种方法:
(* There are 13 card ranks,4 suits *)
datatype rank
= Ace | Two | Three | Four | Five | Six | Seven
| Eight | Nine | Ten | Jack | Queen | King
datatype suit = Hearts | Clubs | Diamonds | Spades
datatype card = Card of suit * rank
fun concatMap f xs = List.concat (List.map f xs)
fun product xs ys = concatMap (fn x => map (fn y => (x,y)) ys) xs
val allCards = map Card
(product
[Hearts,Clubs,Diamonds,Spades]
[Ace,Two,Three,Four,Five,Six,Seven,Eight,Nine,Ten,Jack,Queen,King])
(* Create a new pseudo-random number generator,prng *)
val prng = Random.newgen ()
(* rlist determines a random index in [0 ; length xs[. *)
fun rlist xs = Random.range (0,length xs) prng
(* remove removes the n'th element of a list *)
fun remove (_,[]) = raise Domain
| remove (0,card::library) = library
| remove (n,card::library) = card::remove (n-1,library);
(* randomtake removes and returns the i'th (random) element of a list *)
fun randomtake library =
let val i = rlist library
val card = List.nth (library,i)
val rest = remove (i,library)
in
(card,rest)
end
(* Shuffling is done by removing random cards until there are no cards left *)
fun shuffle [] = []
| shuffle cards =
let val (c,r) = randomtake cards
in
c :: shuffle r
end
使用这些功能,您可以通过执行randomtake allCards
来选择一张随机卡,或者可以选择任意数量的随机卡而无需先shuffle allCards
来选择同一张卡,然后选择顶部的元素。
请注意,这些不是有效的方法。作为练习,您可以实现Fisher-Yates shuffle。