life game
今日、どうにも良い方法が見つからなかったので、大学からの帰りに本屋でプログラミングHaskell読んでライフゲームのヒントを探してみました。
すると
なるほど!まさになるほど、といった感じ。
現在生きているセルをタプルのリストで保持してやればいいんですね!
あとは自分で書けそうだったので、夜のバイトが終わった後、2時間くらい今までずっとカリカリ書いてた。
そのうち1時間くらいは、スマートに出力する方法探してたけど.....
結局綺麗な方法思いつかず、forM_とsplitAtに頼りました。
課題としては、
関数が結構入り組んだ形になってしまったので
もっと完結にパーツ化して見やすくする。
ポイントフリースタイル使うとか。
入出力法のバリエーションを探す
などですかね
import Control.Monad width = 5 height = 5 type Pos = (Int,Int) type Living = [Pos] positions :: [Pos] positions = [(x,y) | x <- [1..width] , y <- [1..height]] start :: Living start = [(2,1),(3,1),(1,2),(3,2),(5,2),(4,3),(1,4),(2,5),(3,5)] surround :: Pos -> [Pos] surround (x,y) = [(x-1,y-1),(x,y-1),(x+1,y-1), (x-1,y), (x+1,y), (x-1,y+1),(x,y+1),(x+1,y+1)] alive :: Pos -> Living -> Int alive pos lives= length.filter (`elem` lives)$surround pos visual :: Living -> IO() visual lives = let lifelist = visualFormat $ map (f.(`elem` lives)) positions in forM_ lifelist print >> putStrLn "" where f a = if a then '*' else '-' visualFormat :: String -> [String] visualFormat [] = [] visualFormat ls = a:visualFormat b where (a,b) = splitAt width ls next :: Living -> Pos -> Pos next lives pos = let n = alive pos lives in case elem pos lives of True | elem n [2,3] -> pos False| n == 3 -> pos otherwise -> (0,0) format :: Living -> Living format = filter (not.(==(0,0))) showNext :: Int -> Living ->IO() showNext 0 _ = print "stop" showNext n lives = do visual lives showNext (n-1) $ format.map (next lives) $ positions main = showNext 10 start