2016-10-12 2 views
0

Ich arbeite an einem Memory-Spiel, wo der Benutzer mit einem 5x5 Gitter von Quadraten präsentiert wird mit 9 von ihnen hervorgehoben. Der Benutzer muss sich dann diese 9 Quadrate merken und auswählen.Memory-Spiel in Elm, randomisiert oder gemischt Raster

Wie erzeuge ich die erwartete/erfolgreiche Board-Konfiguration?

Derzeit habe ich Board als List (List Bool)

In einer imperativen Sprache, wie JS haben, würde ich nur über das Raster iterieren 9 mal zufällig eine Spalten- und Zeilenindex der Auswahl zu mutieren. Das ist in Elm nicht möglich, also bin ich ein bisschen fest.

ein paar Strategien in den Sinn kommen:

Strategie 1

ein Gitter randomisierten generieren

Strategie 2

Verwenden Array und alle Koordinaten mischen, die erste Pick 9.

Hinweis: Ich brauche auch eine Möglichkeit, die Kachel auszuwählen. Es ist also wahrscheinlich Board wird List (List Tile), wobei Tile{ x: Int, y: Int, selected: Bool} ist.

Ich habe das Spiel bereits in Vanille JS geschrieben. Sie können es versuchen, hier aus: http://mruzekw.github.io/recall/

Hier ist der Code, den ich etwas bisher geschrieben habe Umsetzung der Strategie:

module Main exposing (..) 

import Html exposing (..) 
import Html.Attributes exposing (..) 
import Html.Events exposing (..) 
import Html.App as App 
import Random 
import Random.Array 
import Array exposing (..) 


-- model 


type alias Board = 
    Array (Array Bool) 


type alias Tile = 
    { x : Int 
    , y : Int 
    , selected : Bool 
    } 


type alias Model = 
    { board : Board 
    , expectedBoard : Board 
    , gameOver : Bool 
    , playerWon : Bool 
    , turnCount : Int 
    } 


initModel : (Model, Cmd Msg) 
initModel = 
    ({ board = generateSquareMatrix 5 False 
     , expectedBoard = Array.fromList [] 
     , gameOver = False 
     , playerWon = False 
     , turnCount = 0 
     } 
    , Cmd.none 
    ) 


generateSquareMatrix : Int -> Bool -> Array (Array Bool) 
generateSquareMatrix num value = 
    Array.repeat num (Array.repeat num value) 



-- update 


type Msg 
    = SelectTile Bool 
    | RestartGame 
    | SuffleBoard 
    | NewBoard (Array (Array Bool)) 


update : Msg -> Model -> (Model, Cmd Msg) 
update msg model = 
    case (Debug.log "msg" msg) of 
     SelectTile tile -> 
      ({ model 
       | turnCount = model.turnCount + 1 
       } 
      , Cmd.none 
      ) 

     RestartGame -> 
      ({ model 
       | turnCount = 0 
       } 
      , Cmd.none 
      ) 

     SuffleBoard -> 
      (model, Random.generate NewBoard (Random.Array.shuffle model.board)) 

     NewBoard newBoard -> 
      ({ model | board = newBoard } 
      , Cmd.none 
      ) 



-- view 


view : Model -> Html Msg 
view model = 
    div [ class "scoreboard" ] 
     [ h1 [] [ text "Recall" ] 
     , grid model 
     , button [ onClick SuffleBoard ] [ text "New Board" ] 
     , p [] [ text (toString model) ] 
     ] 


grid : Model -> Html Msg 
grid model = 
    div [ class "recall-grid" ] 
     (List.map 
      (\row -> 
       div 
        [ class "recall-grid-row" ] 
        (List.map 
         (\tile -> 
          div [ class "recall-grid-tile", onClick (SelectTile tile) ] [] 
         ) 
         (Array.toList row) 
        ) 
      ) 
      (Array.toList model.board) 
     ) 



-- SUBSCRIPTIONS 


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


main : Program Never 
main = 
    App.program 
     { init = initModel 
     , view = view 
     , update = update 
     , subscriptions = subscriptions 
     } 

Antwort

1

Strategy 2 funktioniert gut, da es Einzigartigkeit der Zufallselemente garantieren.

Wenn es um Zufälligkeit geht, ist es am besten, komplexe Generatoren aus einfachen Generatoren mit Generator-Mapping-Funktionen zu erstellen. Dadurch müssen Sie nicht mehr einen Zufallsgenerator innerhalb des tatsächlichen Generatorcodes verfolgen.

Der erste Generator, den wir brauchen, ist einer, der diese Liste von Array-Indizes erstellt, die ich als Tupel von (Int, Int) beschreiben werde.

indexGenerator : Int -> Int -> Random.Generator (Array (Int, Int)) 
indexGenerator edgeSize sampleSize = 
    List.map (\i -> List.map2 (,) (List.repeat edgeSize i) [0..(edgeSize-1)]) [0..(edgeSize-1)] 
     |> List.concat 
     |> Array.fromList 
     |> Random.Array.shuffle 
     |> Random.map (Array.slice 0 sampleSize) 

Jetzt können wir Random.map, zusammen mit Ihrer ersten Matrix von Falschen verwenden die squareMatrixGenerator zu bauen:

squareMatrixGenerator : Int -> Int -> Bool -> Random.Generator (Array (Array Bool)) 
squareMatrixGenerator edgeSize sampleSize value = 
    let 
     initialMatrix = 
      Array.repeat edgeSize (Array.repeat edgeSize value) 
     invertPoint (x, y) = 
      Array.Extra.update x (Array.Extra.update y not) 
     indexes = 
      indexGenerator edgeSize sampleSize 
    in 
     Random.map (Array.foldl invertPoint initialMatrix) indexes 

Der obige Code stützt sich auch auf das elm-community/array-extra Paket für das Array-Updates.

Sie können es dann während init verwenden, indem Sie einen Samen zu Random.step vorbei und durch die ShuffleBoard Msg bei der Verwendung von Random.generate. Zum Beispiel:

ShuffleBoard -> 
    (model, Random.generate NewBoard (squareMatrixGenerator 9 5 False)) 
+0

Danke, Tschad! Hier gibt es viel zu analysieren. Lass mich damit rennen, wie es läuft. Ich werde kommentieren, wenn ich weitere Fragen habe. –