Elm 中的记忆游戏,随机或随机排列的网格
Memory game in Elm, randomized or shuffled grid
我正在开发一款记忆游戏,用户会看到一个 5x5 的正方形网格,其中 9 个突出显示。然后用户必须记住并 select 那 9 个方块。
如何生成 expected/winning 电路板配置?
目前,我有 Board
作为 List (List Bool)
在像 JS 这样的命令式语言中,我会随机遍历网格 9 次 select 对列和行索引进行变异。这在 Elm 中是不可能的,所以我有点卡住了。
想到了几个策略:
策略 1
生成随机网格
策略 2
使用Array
并打乱所有坐标,选择前9个。
请注意,我还需要一种方法来 select 磁贴,因此 Board
可能会变成 List (List Tile)
,其中 Tile
是 { x: Int, y: Int, selected: Bool}
。
我已经用 vanilla JS 编写了游戏。您可以在这里尝试一下:http://mruzekw.github.io/recall/
这是我到目前为止编写的代码,在某种程度上实现了策略:
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
}
策略 2 工作得很好,因为它将保证随机元素的唯一性。
在处理随机性时,最好使用生成器映射函数从简单生成器构建复杂生成器。这使您不必在实际生成器代码中跟踪随机种子。
我们需要的第一个生成器是构建数组索引列表的生成器,我将其描述为 (Int, Int)
.
的元组
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)
现在我们可以使用 Random.map
以及您的初始 Falses 矩阵来构建 squareMatrixGenerator
:
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
以上代码还依赖于 elm-community/array-extra
包进行数组更新。
您可以在 init
期间通过将种子传递给 Random.step
并在使用 Random.generate
时通过 ShuffleBoard
消息使用它。例如:
ShuffleBoard ->
( model, Random.generate NewBoard (squareMatrixGenerator 9 5 False) )
我正在开发一款记忆游戏,用户会看到一个 5x5 的正方形网格,其中 9 个突出显示。然后用户必须记住并 select 那 9 个方块。
如何生成 expected/winning 电路板配置?
目前,我有 Board
作为 List (List Bool)
在像 JS 这样的命令式语言中,我会随机遍历网格 9 次 select 对列和行索引进行变异。这在 Elm 中是不可能的,所以我有点卡住了。
想到了几个策略:
策略 1
生成随机网格
策略 2
使用Array
并打乱所有坐标,选择前9个。
请注意,我还需要一种方法来 select 磁贴,因此 Board
可能会变成 List (List Tile)
,其中 Tile
是 { x: Int, y: Int, selected: Bool}
。
我已经用 vanilla JS 编写了游戏。您可以在这里尝试一下:http://mruzekw.github.io/recall/
这是我到目前为止编写的代码,在某种程度上实现了策略:
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
}
策略 2 工作得很好,因为它将保证随机元素的唯一性。
在处理随机性时,最好使用生成器映射函数从简单生成器构建复杂生成器。这使您不必在实际生成器代码中跟踪随机种子。
我们需要的第一个生成器是构建数组索引列表的生成器,我将其描述为 (Int, Int)
.
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)
现在我们可以使用 Random.map
以及您的初始 Falses 矩阵来构建 squareMatrixGenerator
:
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
以上代码还依赖于 elm-community/array-extra
包进行数组更新。
您可以在 init
期间通过将种子传递给 Random.step
并在使用 Random.generate
时通过 ShuffleBoard
消息使用它。例如:
ShuffleBoard ->
( model, Random.generate NewBoard (squareMatrixGenerator 9 5 False) )