Как получить случайный элемент в данном списке в 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)