我正在用榆树做一个游戏,并试图随机将N个邪恶的机器人放在一个带有ROWS x COLS细胞的网格上。
我想要的是List(Int,Int)对,它们指定放置N个机器人的位置。
我可以使用
创建坐标对列表makeGrid : Seed -> List (Int, Int)
makeGrid seed =
let gen = list n <| pair (int 0 rows) (int 0 cols)
in
fst (generate gen seed)
没关系。但是,如果我想生成一个唯一对的列表?
我应该采取必要的解决方案来保存一套我的东西 循环通过添加,直到我有足够的?
也许这样的事情(可能是错的,没有在REPL中检查):
makeN : Int -> Seed -> (List (Int, Int), Seed)
makeN n seed =
let gen = list n <| pair (int 0 rows) (int 0 cols)
in
generate gen seed
makeGrid : List(Int, Int) -> Seed -> Int -> List (Int, Int)
makeGrid partial seed n =
case of List.length partial
n -> partial
current ->
let (new_elems, new_seed) = makeN (n - current) seed
makeGrid Set.toList (Set.fromList <| append partial new_elems) new_seed n
感觉不舒服。我考虑过3种选择:
将我的网格列为ROWS * COLS坐标对的列表,其类型为List(Int,Int),然后将其洗牌,并在列表中取出前N对以放置我的机器人。这看起来非常简洁和干净,但是如果我需要的独特点的数量比我的网格小得多,并且如果我的网格很大(因为Fisher-Yates是O(n log(n)),我认为这是低效/坏的。
使用类似this package的内容从网格中进行采样而无需替换,但我需要将网格更改为数组,看起来它会进行大量拆分和拼接数组操作,这看起来很昂贵
使用JS FFI在4行JS循环中实现它。
这些解决方案都没有感觉良好,有什么我想念的吗? 我可能只是将游戏机制改为每个单元都有一个机器人的概率P,这样就可以更容易实现。
答案 0 :(得分:1)
我在elm-random-extra上打开an issue,mgold帮助我开发了类似于问题的函数,然后将其添加到elm-random-extra 2.1.1。非常感谢mgold!
该函数在elm-random-extra的Random.Set中为set
,其类型为:
set : Int -> Generator comparable -> Generator (Set comparable)
您传递了n
,generator
,并从原始generator
返回n
组generator
项内容。例如:
$ fst <| generate (set 5 <| int 0 1000) seed
Set.fromList [286,398,618,961,1000] : Set.Set Int
或回答我原来的问题,(例如)100x100网格上的唯一对:
$ fst <| generate (set 10 <| pair (int 0 100) (int 0 100)) seed
Set.fromList [(2,54),(4,55),(25,50),(35,32),(46,9),(55,9),(62,22),(65,77),(88,74),(95,31)]
: Set.Set ( Int, Int)
有一点需要注意:该函数不知道它所生成的生成器有多少独特元素,因此有可能要求它提供100个唯一数字并给它一个骰子(int 1 6
)生成器,它试图永远得到第7个唯一的数字,导致堆栈溢出可能会卡住。
有两种选择:堆栈溢出崩溃,或返回错误数据,在多次罢工后提前停止。我们选择了第二个。如果连续10次找不到唯一的数字,它将返回到目前为止发现的数字。我认为这符合榆树的“无运行时错误”理念。