榆树指南骰子练习

Elm Guide Dice Exercise

我正在做随机部分的 Elm Guide 练习,但卡在了第 5 步,我必须在骰子确定最终值之前翻转骰子。我正在尝试调用 Cmd,它使用骰子的新值更新视图,只需单击“滚动!”按钮 10 次。并在每次迭代之前放置某种睡眠函数。据我所知,Elm 没有 for、loop 或 while 语句。循环的唯一方法是通过递归,但我无法为此调整我的代码。我的代码如下,有人有什么建议吗?

import Browser
import Html exposing (..)
import Html.Events exposing (..)
import Svg exposing (..)
import Svg.Attributes as SvgAttr exposing (..)
import Random



-- MAIN


main =
  Browser.element
    { init = init
    , update = update
    , subscriptions = subscriptions
    , view = view
    }



-- MODEL


type alias Model =
  { dieFace : Int
  , dieFace2 : Int
  }


init : () -> (Model, Cmd Msg)
init _ =
  ( Model 1 1
  , Cmd.none
  )



-- UPDATE


type Msg
  = Roll
  | NewFace (Int, Int)


update : Msg -> Model -> (Model, Cmd Msg)
update msg model =
  case msg of
    Roll ->
      ( model
      , Random.generate NewFace randomPair
      )

    NewFace (newFace, newFace2) ->
      ( Model newFace newFace2
      , Cmd.none
      )

weightedRoll : Random.Generator Int
weightedRoll =
  Random.weighted
          (1, 1)
          [ (10, 2) 
          , (10, 3) 
          , (10, 4)
          , (20, 5)
          , (40, 6)
          ]
          
          
randomPair : Random.Generator (Int, Int)
randomPair = 
  Random.pair (Random.int 1 6) (Random.int 1 6)
    
    
  
    

-- SUBSCRIPTIONS


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



-- VIEW


view : Model -> Html Msg
view model =
  div [] 
      [ h1 [] [ Html.text (String.fromInt model.dieFace) ]
      , svg
          [ width "120"
          , height "120"
          , viewBox "0 0 120 120"
          ]
        (List.append
          [ rect
            [ x "10"
            , y "10"
            , width "100"
            , height "100"
            , rx "15"
            , ry "15"
            ]
            []
          ]
          (dicesSVG model.dieFace)
        )
      , div []
            [ h1 [] [Html.text (String.fromInt model.dieFace2) ]
            , svg
          [ width "120"
          , height "120"
          , viewBox "0 0 120 120"
          ]
        (List.append
          [ rect
            [ x "10"
            , y "10"
            , width "100"
            , height "100"
            , rx "15"
            , ry "15"
            ]
            []
          ]
          (dicesSVG model.dieFace2)
        )]
      , button [onClick Roll] [Html.text "Roll!"]
      ]
    
    
dicesSVG : Int -> List (Svg Msg)
dicesSVG number =
  case number of
    1 ->
      [ circle [cx "60", cy "60", r "10", fill "white" ] [] ]
      
    2 ->
      [ circle [ cx "35", cy "35", r "10", fill "white" ] []
      , circle [ cx "85", cy "85", r "10", fill "white" ] []
      ]
      
    3 ->
      [ circle [ cx "35", cy "35", r "10", fill "white" ] []
      , circle [ cx "60", cy "60", r "10", fill "white" ] []
      , circle [ cx "85", cy "85", r "10", fill "white" ] []
      ]
      
    4 ->
      [ circle [ cx "35", cy "35", r "10", fill "white" ] []
      , circle [ cx "85", cy "35", r "10", fill "white" ] []
      , circle [ cx "35", cy "85", r "10", fill "white" ] []
      , circle [ cx "85", cy "85", r "10", fill "white" ] []
      ]
      
    5 ->
      [ circle [ cx "35", cy "35", r "10", fill "white" ] []
      , circle [ cx "85", cy "35", r "10", fill "white" ] []
      , circle [ cx "60", cy "60", r "10", fill "white" ] []
      , circle [ cx "35", cy "85", r "10", fill "white" ] []
      , circle [ cx "85", cy "85", r "10", fill "white" ] []
      ]
      
    6 ->
      [ circle [ cx "35", cy "35", r "10", fill "white" ] []
      , circle [ cx "85", cy "35", r "10", fill "white" ] []
      , circle [ cx "35", cy "60", r "10", fill "white" ] []
      , circle [ cx "85", cy "60", r "10", fill "white" ] []
      , circle [ cx "35", cy "85", r "10", fill "white" ] []
      , circle [ cx "85", cy "85", r "10", fill "white" ] []
      ]
      
    _ ->
      []

诀窍主要在于要求运行时向您发送消息。

您可以尝试的第一件事是改变

  NewFace (newFace, newFace2) ->
      ( Model newFace newFace2
      , Cmd.none
      )

  NewFace (newFace, newFace2) ->
      ( Model newFace newFace2
      , Random.generate NewFace randomPair
      )

这有一个永不停止的问题,让你的程序永远旋转...

因此您需要跟踪一些停止条件。也许在您的模型中添加一个字段来跟踪它已经滚动了多少次?然后根据该字段在 Random.generateCmd.none 之间切换。


最后,如果你想在滚动之间有时间延迟,那么

import Task


wait : Float -> msg -> Cmd msg
wait delay msgToCallWhenDone =
  Task.perform (always msg) (Process.sleep delay)

会给你一个 Cmd,它将在 delay 毫秒后调用你给它的任何消息。作为提示,您可能想为此介绍另一条信息。