Problem 23

Extract a given number of randomly selected elements from a list.

Example

randomSelect seed 3 ["Al", "Biff", "Cal", "Dee", "Ed", "Flip"] == ["Cal", "Dee", "Al"]

You must use Elm's Random to implement randomSelect. Use Random.step to generate a pseudo-random number. Random.step takes a Generator and a Seed. The seed is passed as a parameter to randomSelect. You will need to create a generator such as Random.int.

Random.step will return both a randomly generated value from the generator, and a new seed. You must use the new seed for subsequent random numbers.

Unit Test

This unit test uses the Elm Architecture to allow a pseudo-random seed to enter into the pure functional world of Elm. You don't need to understand how this works to implement randomSelect. Because it uses the Elm Architecture it will not run on elm.org/try. Instead, install Elm, compile and run this application on your local machine. See https://guide.elm-lang.org/install.html.

module Main exposing (..)

import Html exposing (..)
import Html.Events exposing (..)
import Random


randomSelect : Random.Seed -> Int -> List a -> ( List a, Random.Seed )
randomSelect seed n list =
    -- your implementation goes here
    ( [], seed )


main : Program Never Model Msg
main =
    Html.program
        { init = init
        , view = view
        , update = update
        , subscriptions = subscriptions
        }


-- MODEL


type alias Model =
    { intSeed : Int
    , tested : Bool
    , passed : Bool
    }


init : ( Model, Cmd Msg )
init =
    ( Model 1 False False, Cmd.none )



-- UPDATE


type Msg
    = Test
    | NewFace Int


update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
    case msg of
        Test ->
            ( model, Random.generate NewFace (Random.int Random.minInt Random.maxInt) )

        NewFace newSeed ->
            ( Model newSeed True (test model.intSeed), Cmd.none )



-- SUBSCRIPTIONS


subscriptions : Model -> Sub Msg
subscriptions model =
    Sub.none



-- VIEW


view : Model -> Html Msg
view model =
    div []
        [ h2 [] [ text (testMsg model.tested model.passed) ]
        , p [] [ text ("Seed value: " ++ (toString (model.intSeed))) ]
        , p [] [ text ("Your die roll is " ++ (toString (Tuple.first (randomSelect (Random.initialSeed model.intSeed) 1 (1..6))))) ]
        , button [ onClick Test ] [ text "Test" ]
        ]


test : Int -> Bool
test intSeed =
    let
        seed =
            Random.initialSeed intSeed

        ( l1, s1 ) =
            randomSelect seed 3 (1..1000)

        ( l2, s2 ) =
            randomSelect seed 3 (1..1000)

        ( l3, s3 ) =
            randomSelect s2 3 (1..1000)

        ( l4, s4 ) =
            randomSelect s3 9 (1..9)

        ( l5, s5 ) =
            randomSelect s4 3 [ "a", "b" ]

        ( l6, s6 ) =
            randomSelect s5 0 [ 'a', 'b' ]

        ( l7, s7 ) =
            randomSelect s6 -1 [ 'a', 'b' ]

        ( l8, s8 ) =
            randomSelect s7 1 [ 'a', 'b' ]
    in
        List.all ((==) True)
            [ List.sort l1 == List.sort l2
            , l1 == l2
            , l2 /= l3
              -- a billion to one that this won't match
            , List.sort l4 == 1..9
            , List.sort l5 == [ "a", "b" ]
            , l6 == []
            , l7 == []
            ]


testMsg : Bool -> Bool -> String
testMsg tested passed =
    if tested then
        if passed then
            "Your implementation passed all tests."
        else
            "Your implementation failed at least one test."
    else
        "Click the test button below"



(..) : Int -> Int -> List Int
(..) start end =
    List.range start end

Hints

  1. elementAt and dropAt from Problem 3 and Problem 20 could prove useful.

Solutions

Solutions

results matching ""

    No results matching ""