ラングトンのアリの描画
Posted feedbacks - Haskell
Haskellで実装。要:UTF8-String
$ runhaskell langton.hs 100 100 20
とかすると、100x100マスの世界の模様を20ステップごとに表示してくれます。最後の数字を省略すると律儀に一世代ごとに印字します。
無限リストばんざい!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 | import qualified System.IO.UTF8 as U
import System.Environment (getArgs, getProgName)
import Control.Monad.State
import qualified Data.Map as M
import Data.List (sortBy, groupBy)
type Point = (Int, Int)
type Direction = (Int, Int)
data Ant = Ant {pos::Point, direction::Direction} deriving Show
data Color = White | Black
data AntsState = AS { world::(M.Map Point Color), ants::[Ant], wrap :: Bool, height::Int, width::Int, generation::Int }
instance Show Color where
show Black = "■"
show White = "□"
cmp f ((_,a),_) ((_,b),_) = f a b
instance Show AntsState where
show AS{world=wd, generation=g} = "gen: " ++ show g ++ "\n" ++ (unlines $ map (concatMap(show.snd)) $ groupBy (cmp (==)) $ (sortBy (cmp compare) $ M.toList wd))
main = do args <- getArgs
pname <- getProgName
case args of
(x:y:s:_) -> mapM_ (U.putStrLn . show . head) $ iterate (drop (read s)) $ evolutions (read x) (read y)
(x:y:_) -> mapM_ (U.putStrLn . show) $ evolutions (read x) (read y)
_ -> putStrLn ("usage: " ++ pname ++ " height width [step]")
makeAnt x y = Ant {pos=(x, y), direction=(0,-1)}
makeWorld height width ants wrap = AS {
world = M.fromList [((x,y), White) | x <- [0..width-1], y <- [0..height-1]],
ants = ants,
height = height,
width = width,
generation = 0,
wrap = wrap
}
proceed :: State AntsState AntsState
proceed = do st@AS{ants=as,generation=g} <- get
a' <- mapM procAnts as
st <- get
let s = st{ants = a',generation=g+1}
put s
return s
procAnts ant@Ant{pos=p@(x,y), direction=(dx,dy)} = do
w@AS{world=wd, wrap=wr, width=wdt, height=h} <- get
let pt = ((x+dx) `mod` wdt, (y+dy) ` mod` h)
st = maybe Black id $ M.lookup pt wd
(dr, s') = case st of
Black -> ((dy, -dx), White)
_ -> ((-dy, dx), Black)
put w{world= M.insert pt s' wd}
return ant{pos = pt, direction = dr}
evolutions width height = iterate (execState proceed) (makeWorld width height [makeAnt (width*3`div`5) (height*2`div`5)] True)
|
Haskellに翻訳。
C++からの「翻訳」なのでHaskellらしくないかもしれません。
C++からの「翻訳」なのでHaskellらしくないかもしれません。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 | import Graphics.UI.GLUT
import Control.Exception
import System.Exit
import Data.IORef
interval = 0
windowWidth = 320::GLsizei
windowHeight = 240::GLsizei
data Direction = North | East | South | West deriving Enum
data Ant = Ant Position Direction
turnRight :: Direction -> Direction
turnRight d = toEnum (((fromEnum d) + 1) `mod` 4)
turnLeft :: Direction -> Direction
turnLeft d = toEnum (((fromEnum d) + 3) `mod` 4)
initialEnv :: (Ant, [Position])
initialEnv = (Ant (Position (windowWidth `div` 2) (windowHeight `div` 2)) East, [])
convd :: (Integral a) => a -> GLdouble
convd = fromInteger.toInteger
forward (Position x y) North = Position x (y - 1)
forward (Position x y) East = Position (x + 1) y
forward (Position x y) South = Position x (y + 1)
forward (Position x y) West = Position (x - 1) y
draw env = do
(_, ps) <- readIORef env
clearColor $= Color4 1.0 1.0 1.0 1.0
clear [ColorBuffer]
color $ Color3 (0.0::Double) 0.0 0.0
renderPrimitive Points $ mapM_ (¥ (Position x y) -> vertex $ Vertex2 x y) ps
swapBuffers
update (Ant pos dir, ps) =
if elem pos ps
then (Ant (forward pos (turnRight dir)) (turnRight dir), [p | p <- ps, p /= pos])
else (Ant (forward pos (turnLeft dir)) (turnLeft dir), pos:ps)
-- event handlers
display env = do
draw env
reshape (Size w h) = do
viewport $= (Position 0 0, Size w h)
loadIdentity
ortho (-0.5) ((convd w) - 0.5) ((convd h) - 0.5) (-0.5) (-1.0) (1.0)
keyboardMouse key keystate modifiers position = do
case key of
Char 'q' -> throwIO $ ExitException ExitSuccess
_ -> return ()
timer env = do
modifyIORef env $ update
draw env
addTimerCallback interval $ timer env
main = do
env <- newIORef initialEnv
getArgsAndInitialize
initialDisplayMode $= [RGBAMode, DoubleBuffered]
initialWindowPosition $= Position 100 100
initialWindowSize $= Size windowWidth windowHeight
createWindow "doukaku#276"
displayCallback $= display env
reshapeCallback $= Just reshape
keyboardMouseCallback $= Just keyboardMouse
addTimerCallback interval $ timer env
mainLoop
|





Songmu #9331() [ JavaScript ] Rating8/10=0.80
- 黒いマスにアリがいた場合、90°右に方向転換し、そのマスの色を反転させ、1マス前進する。
- 白いマスにアリがいた場合、90°左に方向転換し、そのマスの色を反転させ、1マス前進する。
詳しくはWikipedia等で調べるか、参考ページに拙作のデモがありますのでご覧下さい。
see: JavaScriptでラングトンの蟻
Rating8/10=0.80-0+
[ reply ]