嗨,我需要帮助才能获得monad的最后状态。所以该程序基于Game of Life程序与一些用户交互。我现在正在做的是一个允许用户手动输入x和y坐标以使细胞存活的功能。问题是我不知道如何获得最后一块板。获得最后一个状态是一个简单的原因吗?最后一块板?或许我应该这么不同呢?我感谢所有的回复!
到目前为止的计划:
import Control.Monad.State
import Data.List
import System.IO
import Data.Char
import Data.List.Split
data CellState = Dead | Alive deriving (Eq)
data Cell = Cell CellState Int deriving (Eq)
data Row = Row [Cell] Int deriving (Eq)
data Grid = Grid [Row]
type GridState a = State Grid a
instance Show Grid where
show (Grid rows) = do
unlines $ map show rows
instance Show Row where
show (Row cells n) = (show n) ++ ": " ++ (unwords $ map show cells)
instance Show Cell where
show (Cell color _) = show color
instance Show CellState where
show c = case c of
Dead -> "_"
Alive -> "#"
main :: IO()
main = do
let menu = do
putStrLn "Please execute following command or exit program: "
putStrLn "1. Initialize new grid - 'y'"
putStrLn "2. Create new grid - 'c n'"
putStrLn "3. Set cell Alive, x y - 'n x y'"
putStrLn "4. Quit the program - 'q'"
action <- getLine
if action == "q"
then return ()
else if (action == "y")
then do
print $ execState initializeGrid (createGrid 9)
menu
else if (fst (c action))
then do
let s = (snd (c action))
let first = read (s !! 1) :: Int
print $ execState initializeGrid (createGrid first)
menu
else if (fst (n action))
then do
let s = (snd (n action))
let first = read (s !! 1) :: Int
let second = read (s !! 2) :: Int
let list = --RIGHT HERE I WANT TO GET THE LAST GRID
print $ execState updateAlive list
else do
putStrLn "No"
menu
menu
n :: String -> (Bool, [String])
n s = do
let list = splitOn " " s
let char = (list !! 0)
let first = all isDigit (list !! 1)
let second = all isDigit (list !! 2)
let l = length list
if (char == "n") && first && second && (l == 3)
then (True, list)
else (False, list)
c :: String -> (Bool, [String])
c s = do
let list = splitOn " " s
let char = (list !! 0)
let first = all isDigit (list !! 1)
let l = length list
if (char == "c") && first && (l == 2)
then (True, list)
else (False, list)
updateAlive :: Int -> Int -> GridState ()
updateAlive x y = do
setAliveCell x y
initializeGrid :: GridState()
initializeGrid = do
setAliveCell 1 1
setAliveCell 1 2
setAliveCell 2 1
createGrid :: Int -> Grid
createGrid n = Grid (map row (take n [0, 1..])) where
row = Row (map cell (take n [0, 1..]))
cell = Cell Dead
setAliveCell :: Int -> Int -> GridState()
setAliveCell x y = do
grid <- get
let rows = getRows grid
cells = getCells (rows !! x)
updateState = Grid (replaceCellState rows x (Row (replaceCellState cells y (Cell Alive y)) x))
put updateState
setDeadCell :: Int -> Int -> GridState()
setDeadCell x y = do
grid <- get
let rows = getRows grid
cells = getCells (rows !! x)
updateState = Grid (replaceCellState rows x (Row (replaceCellState cells y (Cell Dead y )) x))
put updateState
isAlive :: Cell -> Bool
isAlive (Cell a _) = a == Alive
getCells :: Row -> [Cell]
getCells (Row c _) = c
getRows :: Grid -> [Row]
getRows (Grid r) = r
replaceCellState :: [a] -> Int -> a -> [a]
replaceCellState list pos replacement =
let (x, _:xs) = splitAt pos list
in x ++ replacement : xs
playRound :: Grid -> Grid
playRound (Grid rows) = Grid $ map (updateRow rows) rows
updateRow :: [Row] -> Row -> Row
updateRow rows row@(Row cells p) = Row (map (updateCell rows row) cells) p
updateCell :: [Row] -> Row -> Cell -> Cell
updateCell rows row cell@(Cell _ position) =
let upperRowCells = getCells $ previous rows row
upperCell = upperRowCells !! position
lowerRowCells = getCells $ next rows row
lowerCell = lowerRowCells !! position
neighbourCells = [upperCell, lowerCell] ++
getNextPrevious (getCells row) cell ++
getNextPrevious upperRowCells upperCell ++
getNextPrevious lowerRowCells lowerCell
countLivingNeighbours = length $ filter (==Alive) $ map getCellColor neighbourCells
isLiving = getCellColor cell == Alive
in Cell (calcCellState isLiving countLivingNeighbours) position
getCellColor :: Cell -> CellState
getCellColor (Cell c _) = c
calcCellState :: Bool -> Int -> CellState
calcCellState living livingNeighbours
| living && livingNeighbours < 2 = Dead
| living && livingNeighbours <= 3 = Alive
| living && livingNeighbours > 3 = Dead
| not living && livingNeighbours == 3 = Alive
| otherwise = Dead
getNextPrevious :: Eq a => [a] -> a -> [a]
getNextPrevious l e = [next l e, previous l e]
next :: Eq a => [a] -> a -> a
next l@(x:_) e = case dropWhile (/= e) l of
(_:y:_) -> y
_ -> x
previous :: Eq a => [a] -> a -> a
previous l e = case takeWhile (/= e) l of
[] -> last l
x -> last x