Как получить случайный элемент в данном списке в Elm?

Я строю скользящую головоломку:

введите описание изображения здесь

Из этой исходной позиции я бы хотел перетасовать головоломку, скажем, 100 ходов.

Я бы хотел, чтобы головоломка перемешивалась по-разному каждый раз.

Это, вероятно, означает, что мне нужно позвонить Random.initialSeed каждый раз с другим номером, что означает, что мне нужно использовать что-то вроде текущего времени.

К сожалению, я не мог найти, как узнать текущее время.

В каждом данном состоянии у меня есть список возможных ходов. Например, в исходной позиции выше: [MoveRight, MoveDown]

Итак, в основном, мой вопрос: как получить случайный элемент в данном списке?

Share-Elm пример будет оценен.

3 ответа

Решение

Грубый ответ (сейчас не рядом с компилятором):

Если вы хотите изменить семена в зависимости от текущего времени, добавьте Time.every к вашему графику сигналов:

http://package.elm-lang.org/packages/elm-lang/core/2.1.0/Time

Сохраните последнюю увиденную временную метку в своей модели, затем, когда вам нужно будет перемешать, используйте ее для начального числа случайных чисел. Создайте целое число в диапазоне [1, длина списка], а затем выберите элемент этого индекса.

Надеюсь, что намек достаточно, пожалуйста, кричите, если это не так, и я уточню, когда у меня будет шанс.

Это пересмотр ответа pdamoc. Она более точно следует за "Архитектурой вяза", но, что более важно, она сохраняет случайное начальное число от печати к печати. Если вы продолжите использовать начальное семя, вы не получите случайности. Я получил только четные или нечетные числа (получил четные, обновленные, получил шансы) с другой версией. Важно позвонить Random.initialSeed только один раз в вашей программе, обычно в определении исходной модели.

Существует также библиотека (которую я написал), которая обрабатывает случайные операции над массивами.

import Html exposing (..) 
import Html.Events exposing (onClick) 
import Random exposing (initialSeed, int, generate, Seed)

type alias Model = 
  { list : List Int , currentElement : Maybe Int, seed : Seed}

init : Model 
init = {list = [1..10], currentElement = Nothing, seed = initialSeed 42 } 

type Action = NoOp | Click

actions : Signal.Mailbox Action
actions = Signal.mailbox NoOp

update : Action -> Model -> Model
update action model =
  case action of
    NoOp -> model
    Click ->
      let gen = Random.int 0 (List.length model.list - 1)
          -- since we know the list is constant we don't have to
          -- redefine the generator every time, but we will anyway
          (i, seed) = Random.generate gen model.seed
          elem = List.drop i model.list |> List.head
      in {model| currentElement <- elem, seed <- seed}

model : Signal Model
model = Signal.foldp update init actions.signal

view : Signal.Address Action -> Model -> Html
view address model = 
  let 
    current = model.currentElement
              |> Maybe.map toString
              |> Maybe.withDefault "NONE"
  in 
    div [] 
      [ text  <| toString model.list
      , br [] []
      , text  <| "Current Element: " ++ current
      , br [] []
      , button [onClick address Click ] [text "Click for Random Element"]
      ]

main = Signal.map (view actions.address) model

Я создал вариант примера StartApp от Elm, который включает время для каждого события, только когда событие происходит.

https://gist.github.com/z5h/41ca436679591b6c3e51

Ваша функция обновления теперь будет выглядеть так:

update : action -> Time -> model -> (model, Effects action)

Другие вопросы по тегам