Haskell - 获得最后一个州/董事会

时间:2017-11-14 20:13:14

标签: haskell

嗨,我需要帮助才能获得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

0 个答案:

没有答案