榆树 - 没有重复的随机数列表

时间:2015-12-07 01:44:20

标签: random elm

我正在用榆树做一个游戏,并试图随机将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种选择:

  1. 将我的网格列为ROWS * COLS坐标对的列表,其类型为List(Int,Int),然后将其洗牌,并在列表中取出前N对以放置我的机器人。这看起来非常简洁和干净,但是如果我需要的独特点的数量比我的网格小得多,并且如果我的网格很大(因为Fisher-Yates是O(n log(n)),我认为这是低效/坏的。

  2. 使用类似this package的内容从网格中进行采样而无需替换,但我需要将网格更改为数组,看起来它会进行大量拆分和拼接数组操作,这看起来很昂贵

  3. 使用JS FFI在4行JS循环中实现它。

  4. 这些解决方案都没有感觉良好,有什么我想念的吗? 我可能只是将游戏机制改为每个单元都有一个机器人的概率P,这样就可以更容易实现。

1 个答案:

答案 0 :(得分:1)

我在elm-random-extra上打开an issuemgold帮助我开发了类似于问题的函数,然后将其添加到elm-random-extra 2.1.1。非常感谢mgold!

该函数在elm-random-extra的Random.Set中为set,其类型为:

set : Int -> Generator comparable -> Generator (Set comparable)

您传递了ngenerator,并从原始generator返回ngenerator项内容。例如:

$ 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次找不到唯一的数字,它将返回到目前为止发现的数字。我认为这符合榆树的“无运行时错误”理念。

相关问题