Reputation: 171351
I'm building a sliding puzzle game:
From this initial position, I'd like to shuffle the puzzle, say 100 moves.
I'd like the puzzle to be shuffled differently each time.
This probably means that I need to call Random.initialSeed
with a different number every time, which means that I need to use something like the current time.
Unfortunately, I couldn't find how to get the current time.
In every given state, I have a list of possible moves. For example, in the initial position above: [MoveRight, MoveDown]
So, basically, my question is: how to get a random element in a given List?
share-elm example would be appreciated.
Upvotes: 1
Views: 1419
Reputation: 24409
I have created a variant of Elm's StartApp sample, which includes the Time for every event, only when an event occurs.
https://gist.github.com/z5h/41ca436679591b6c3e51
Your update function will now look like:
update : action -> Time -> model -> (model, Effects action)
Upvotes: 0
Reputation: 6366
This is a revision of pdamoc's answer. It follows The Elm Architecture more closely, but more importantly, it saves the random seed from press to press. If you keep using an initial seed, you won't get randomness. I got only even or odd numbers (got evens, refreshed, got odds) with the other version. It's important to call Random.initialSeed
only once in your program, usually in the definition of the initial model.
There is also a library (which I wrote) that handles random operations on Arrays.
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
Upvotes: 7
Reputation: 366
Rough answer (not near a compiler right now):
If you want to vary the seed based on the current time, add Time.every
to your signal graph:
http://package.elm-lang.org/packages/elm-lang/core/2.1.0/Time#every
Keep the last seen timestamp in your model, then, when you need to shuffle, use it to seed your random. Generate an integer in the range [1, length list], and then pick the element of that index.
Hope that's enough of a hint, please yell if it isn't and I will elaborate when I get chance.
Upvotes: 2