module IdeaFight.Shuffle exposing (shuffle)

import Random exposing (Generator)


extractValueHelper : List a -> Int -> List a -> ( a, List a )
extractValueHelper values index accumulator =
    case ( index, values ) of
        ( _, [] ) ->
            Debug.crash "Out of values to extract"

        ( 0, head :: tail ) ->
            ( head, List.append (List.reverse accumulator) tail )

        ( _, head :: tail ) ->
            extractValueHelper tail (index - 1) <| head :: accumulator


extractValue : List a -> Int -> ( a, List a )
extractValue values index =
    extractValueHelper values index []


shuffle : List a -> Generator (List a)
shuffle values =
    case values of
        [] ->
            Random.map (\_ -> []) Random.bool

        values ->
            let
                randomIndexGenerator =
                    Random.int 0 <| List.length values - 1

                extractAndRecurse =
                    \index ->
                        let
                            ( randomHead, remainder ) =
                                extractValue values index

                            remainderGen =
                                shuffle remainder
                        in
                        Random.map (\randomTail -> randomHead :: randomTail) remainderGen
            in
            Random.andThen extractAndRecurse randomIndexGenerator

module IdeaFight.Shuffle exposing (shuffle)

import Random exposing (Generator)


extractValueHelper : a -> List a -> Int -> List a -> ( a, List a )
extractValueHelper first_value rest_values index accumulator =
    case ( index, rest_values ) of
        ( 0, _) ->
            ( first_value, List.append (List.reverse accumulator) rest_values )

        ( _, []) ->
            ( first_value, List.reverse accumulator )

        ( _, head :: tail ) ->
            extractValueHelper head tail (index - 1) <| first_value :: accumulator


extractValue : a -> List a -> Int -> ( a, List a )
extractValue first_value rest_values index =
    extractValueHelper first_value rest_values index []


shuffle : List a -> Generator (List a)
shuffle values =
    case values of
        [] ->
            Random.constant []

        (first_value :: rest_values) ->
            let
                randomIndexGenerator =
                    Random.int 0 <| List.length rest_values

                extractAndRecurse =
                    \index ->
                        let
                            ( randomHead, remainder ) =
                                extractValue first_value rest_values index

                            remainderGen =
                                shuffle remainder
                        in
                        Random.map (\randomTail -> randomHead :: randomTail) remainderGen
            in
            Random.andThen extractAndRecurse randomIndexGenerator

Rearrange types in shuffle to avoid crash
Rearrange types in shuffle to avoid crash

Debug.crash was removed from Elm 0.19, so I needed to work around this.
In reality, extractValueHelper and extractValue should never get passed
empty lists, and the Debug.crash invocation was meant to make things
typecheck in this case - so instead we can just use some type magic to
require a non-empty list be passed
