Langton's ant: Difference between revisions
Content added Content deleted
m (→{{header|Sidef}}: minor code simplifications) |
(→{{header|Haskell}}: Replaced by more transparent and idiomatic solution) |
||
Line 2,912: | Line 2,912: | ||
=={{header|Haskell}}== |
=={{header|Haskell}}== |
||
The set of black cells is represented as a set of points. Complementary set is regarded as white cells. |
|||
<lang Haskell>data Color = Black | White |
|||
deriving (Read, Show, Enum, Eq, Ord) |
|||
Necessary import: |
|||
putCell c = putStr (case c of Black -> "#" |
|||
White -> ".") |
|||
<lang Haskell>import Data.Set (member,insert,delete,Set)</lang> |
|||
toggle :: Color -> Color |
|||
toggle color = toEnum $ 1 - fromEnum color |
|||
In order to express the ant's algorithm literally we define two operators: |
|||
<lang Haskell>-- functional sequence |
|||
data Dir = East | North | West | South |
|||
(>>>) = flip (.) |
|||
deriving (Read, Show, Enum, Eq, Ord) |
|||
-- functional choice |
|||
turnLeft South = East |
|||
p ?>> (f, g) = \x -> if p x then f x else g x</lang> |
|||
turnLeft dir = succ dir |
|||
Finally define the datatype representing the state of ant and ant's universe |
|||
turnRight East = South |
|||
<lang Haskell>data State = State { antPosition :: Point |
|||
turnRight dir = pred dir |
|||
, antDirection :: Point |
|||
, getMesh :: Set Point }</lang> |
|||
Now we are ready to express the main part of the algorithm |
|||
data Pos = Pos { x :: Int, y :: Int } |
|||
<lang Haskell>step :: State -> State |
|||
deriving (Read) |
|||
step = isBlack ?>> (setWhite >>> turnRight, |
|||
setBlack >>> turnLeft) >>> move |
|||
where |
|||
isBlack (State p _ m) = member p m |
|||
setBlack (State p d m) = State p d (insert p m) |
|||
setWhite (State p d m) = State p d (delete p m) |
|||
turnRight (State p (x,y) m) = State p (y,-x) m |
|||
turnLeft (State p (x,y) m) = State p (-y,x) m |
|||
move (State (x,y) (dx,dy) m) = State (x+dx, y+dy) (dx, dy) m</lang> |
|||
That's it. |
|||
instance Show Pos where |
|||
show p@(Pos x y) = "(" ++ (show x) ++ "," ++ (show y) ++ ")" |
|||
Here is the solution of the task: |
|||
-- Return the new position after moving one unit in the given direction |
|||
<lang Haskell>task :: State -> State |
|||
moveOne pos@(Pos x y) dir = |
|||
task = iterate step |
|||
case dir of |
|||
>>> dropWhile ((< 50) . distance . antPosition) |
|||
East -> Pos (x+1) y |
|||
>>> head >>> getPosition |
|||
where distance (x,y) = max (abs x) (abs y)</lang> |
|||
North -> Pos x (y-1) |
|||
For given initial configuration it returns the set of black cells at the end of iterations. |
|||
-- Grid is just a list of lists |
|||
type Grid = [[Color]] |
|||
We can display it graphically using Gloss library |
|||
colorAt g p@(Pos x y) = (g !! y) !! x |
|||
<lang haskell>import Graphics.Gloss |
|||
main = display w white (draw (task initial)) |
|||
replaceNth n newVal (x:xs) |
|||
where |
|||
| n == 0 = newVal:xs |
|||
w = InWindow "Ant" (400,400) (0,0) |
|||
initial = State (0,0) (1,0) mempty |
|||
draw = foldMap drawCell |
|||
drawCell (x,y) = Translate (10*x) (10*y) $ rectangleSolid 10 10</lang> |
|||
Or animate the ant's trajectory |
|||
toggleCell g p@(Pos x y) = |
|||
<lang haskell>main = simulate w white 500 initial draw (\_ _ -> step) |
|||
let newVal = toggle $ colorAt g p |
|||
where |
|||
in replaceNth y (replaceNth x newVal (g !! y)) g |
|||
w = InWindow "Ant" (400,400) (0,0) |
|||
initial = State (0,0) (1,0) mempty |
|||
printRow r = do { mapM_ putCell r ; putStrLn "" } |
|||
draw (State p _ s) = pictures [foldMap drawCell s, color red $ drawCell p] |
|||
drawCell (x,y) = Translate (10*x) (10*y) $ rectangleSolid 10 10</lang> |
|||
printGrid g = mapM_ printRow g |
|||
data State = State { move :: Int, pos :: Pos, dir :: Dir, grid :: Grid } |
|||
printState s = do { |
|||
putStrLn $ show s; |
|||
printGrid $ grid s |
|||
} |
|||
instance Show State where |
|||
show s@(State m p@(Pos x y) d g) = |
|||
"Move: " ++ (show m) ++ " Pos: " ++ (show p) ++ " Dir: " ++ (show d) |
|||
nextState s@(State m p@(Pos x y) d g) = |
|||
let color = colorAt g p |
|||
new_d = case color of White -> (turnRight d) |
|||
Black -> (turnLeft d) |
|||
new_m = m + 1 |
|||
new_p = moveOne p new_d |
|||
new_g = toggleCell g p |
|||
in State new_m new_p new_d new_g |
|||
inRange size s@(State m p@(Pos x y) d g) = |
|||
x >= 0 && x < size && y >= 0 && y < size |
|||
initialState size = (State 0 (Pos (size`div`2) (size`div`2)) East [ [ White | x <- [1..size] ] | y <- [1..size] ]) |
|||
--- main |
|||
size = 100 |
|||
allStates = initialState size : [nextState s | s <- allStates] |
|||
main = printState $ last $ takeWhile (inRange size) allStates</lang> |
|||
=={{header|Icon}} and {{header|Unicon}}== |
=={{header|Icon}} and {{header|Unicon}}== |