{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE BangPatterns #-}
{-|
Module      : Graphics.WorldTurtle.Commands
Description : The commands used 
Copyright   : (c) Archibald Neil MacDonald, 2020
License     : BSD3
Maintainer  : FortOyer@hotmail.co.uk
Stability   : experimental
Portability : POSIX

This module contains all commands used to create, move and 
manipulate a turtle.

-}
module Graphics.WorldTurtle.Commands
  (
  -- * Creating a turtle.

    Turtle
  , makeTurtle
  , makeTurtle'
  -- * Movement commands.

  , P.Point
  , forward
  , fd
  , backward
  , bk
  , left
  , lt
  , right
  , rt
  , Graphics.WorldTurtle.Commands.circle
  , goto
  , setPosition
  , home
  , setHeading
  , setSpeed
  , setRotationSpeed
  -- * Styling commands.

  , stamp
  , representation
  -- * Query turtle's state.

  , position
  , heading
  , speed
  , rotationSpeed
  , penColor
  , penDown
  , penSize
  , visible
  -- * Set rendering state.

  , setPenColor
  , setPenDown
  , setPenSize
  , setRepresentation
  , setVisible
  -- * Canvas commands.

  , clear
  , sleep
  -- * Common constants

  , east
  , north
  , west
  , south
  ) where

import Data.Maybe (fromMaybe)

import Control.Lens
import Control.Monad

import Graphics.WorldTurtle.Shapes

import Graphics.WorldTurtle.Internal.Commands
import Graphics.WorldTurtle.Internal.Sequence

import qualified Graphics.WorldTurtle.Internal.Turtle as T
import qualified Graphics.WorldTurtle.Internal.Coords as P

import Graphics.Gloss.Data.Color (Color, black)

import Graphics.Gloss.Data.Picture

{- |
Creates a new `Turtle` and displays it on the canvas. This turtle can then be
manipulated! For example, to create a turtle and then move the turtle forward:

   @
    main:: IO ()
    main = runTurtle $ do
      t <- makeTurtle
      forward 90 t
   @

The default turtle starts at position (0, 0) and is orientated `north`.

-}
makeTurtle :: TurtleCommand Turtle
makeTurtle :: TurtleCommand Turtle
makeTurtle = SeqC Turtle -> TurtleCommand Turtle
forall a. SeqC a -> TurtleCommand a
TurtleCommand SeqC Turtle
forall b. SequenceCommand b Turtle
generateTurtle

{-| This variant of `makeTurtle` takes a starting position, a starting 
    orientation, and a color to apply to the turtle and the turtle's pen.

    @
      myCommand :: TurtleCommand ()
      myCommand = do
        t1 <- makeTurtle' (0, 0)  0 green
        t2 <- makeTurtle' (0, 0) 90 red
        forward 90 t1 \<|\> forward 90 t2
    @

    See `makeTurtle`.
-}
makeTurtle' :: Point -- ^ Initial position of the turtle.

            -> Float -- ^ Initial heading of the turtle.

            -> Color -- ^ Color of the turtle and the turtle's pen.

            -> TurtleCommand Turtle -- ^ The generated turtle.

makeTurtle' :: Point -> Float -> Color -> TurtleCommand Turtle
makeTurtle' Point
p Float
f Color
c = SeqC Turtle -> TurtleCommand Turtle
forall a. SeqC a -> TurtleCommand a
TurtleCommand (SeqC Turtle -> TurtleCommand Turtle)
-> SeqC Turtle -> TurtleCommand Turtle
forall a b. (a -> b) -> a -> b
$ do 
  Turtle
turtle <- SeqC Turtle
forall b. SequenceCommand b Turtle
generateTurtle
  let ts :: (TurtleData -> Identity TurtleData) -> TSC b -> Identity (TSC b)
ts = Turtle
-> (TurtleData -> Identity TurtleData) -> TSC b -> Identity (TSC b)
forall (f :: * -> *) b.
Applicative f =>
Turtle -> (TurtleData -> f TurtleData) -> TSC b -> f (TSC b)
turtLens_ Turtle
turtle
  (TurtleData -> Identity TurtleData)
-> TSC (AlmostVal ()) -> Identity (TSC (AlmostVal ()))
forall b.
(TurtleData -> Identity TurtleData) -> TSC b -> Identity (TSC b)
ts ((TurtleData -> Identity TurtleData)
 -> TSC (AlmostVal ()) -> Identity (TSC (AlmostVal ())))
-> ((Point -> Identity Point) -> TurtleData -> Identity TurtleData)
-> (Point -> Identity Point)
-> TSC (AlmostVal ())
-> Identity (TSC (AlmostVal ()))
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Point -> Identity Point) -> TurtleData -> Identity TurtleData
Lens' TurtleData Point
T.position       ((Point -> Identity Point)
 -> TSC (AlmostVal ()) -> Identity (TSC (AlmostVal ())))
-> Point -> ContT (AlmostVal ()) (TurtleState (AlmostVal ())) ()
forall s (m :: * -> *) a b.
MonadState s m =>
ASetter s s a b -> b -> m ()
.= Point
p
  (TurtleData -> Identity TurtleData)
-> TSC (AlmostVal ()) -> Identity (TSC (AlmostVal ()))
forall b.
(TurtleData -> Identity TurtleData) -> TSC b -> Identity (TSC b)
ts ((TurtleData -> Identity TurtleData)
 -> TSC (AlmostVal ()) -> Identity (TSC (AlmostVal ())))
-> ((Float -> Identity Float) -> TurtleData -> Identity TurtleData)
-> (Float -> Identity Float)
-> TSC (AlmostVal ())
-> Identity (TSC (AlmostVal ()))
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Float -> Identity Float) -> TurtleData -> Identity TurtleData
Lens' TurtleData Float
T.heading        ((Float -> Identity Float)
 -> TSC (AlmostVal ()) -> Identity (TSC (AlmostVal ())))
-> Float -> ContT (AlmostVal ()) (TurtleState (AlmostVal ())) ()
forall s (m :: * -> *) a b.
MonadState s m =>
ASetter s s a b -> b -> m ()
.= Float
f
  (TurtleData -> Identity TurtleData)
-> TSC (AlmostVal ()) -> Identity (TSC (AlmostVal ()))
forall b.
(TurtleData -> Identity TurtleData) -> TSC b -> Identity (TSC b)
ts ((TurtleData -> Identity TurtleData)
 -> TSC (AlmostVal ()) -> Identity (TSC (AlmostVal ())))
-> ((Picture -> Identity Picture)
    -> TurtleData -> Identity TurtleData)
-> (Picture -> Identity Picture)
-> TSC (AlmostVal ())
-> Identity (TSC (AlmostVal ()))
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Picture -> Identity Picture) -> TurtleData -> Identity TurtleData
Lens' TurtleData Picture
T.representation ((Picture -> Identity Picture)
 -> TSC (AlmostVal ()) -> Identity (TSC (AlmostVal ())))
-> Picture -> ContT (AlmostVal ()) (TurtleState (AlmostVal ())) ()
forall s (m :: * -> *) a b.
MonadState s m =>
ASetter s s a b -> b -> m ()
.= Color -> Color -> Picture
turtleArrow Color
black Color
c
  (TurtleData -> Identity TurtleData)
-> TSC (AlmostVal ()) -> Identity (TSC (AlmostVal ()))
forall b.
(TurtleData -> Identity TurtleData) -> TSC b -> Identity (TSC b)
ts ((TurtleData -> Identity TurtleData)
 -> TSC (AlmostVal ()) -> Identity (TSC (AlmostVal ())))
-> ((Color -> Identity Color) -> TurtleData -> Identity TurtleData)
-> (Color -> Identity Color)
-> TSC (AlmostVal ())
-> Identity (TSC (AlmostVal ()))
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Color -> Identity Color) -> TurtleData -> Identity TurtleData
Lens' TurtleData Color
T.penColor       ((Color -> Identity Color)
 -> TSC (AlmostVal ()) -> Identity (TSC (AlmostVal ())))
-> Color -> ContT (AlmostVal ()) (TurtleState (AlmostVal ())) ()
forall s (m :: * -> *) a b.
MonadState s m =>
ASetter s s a b -> b -> m ()
.= Color
c
  Turtle -> SeqC Turtle
forall (m :: * -> *) a. Monad m => a -> m a
return Turtle
turtle

-- | Move the turtle backward by the specified @distance@, in the direction the 

--   turtle is headed.

backward :: Float -- ^ Distance to move the turtle.

         -> Turtle -- ^ The turtle to move.

         -> TurtleCommand ()
backward :: Float -> Turtle -> TurtleCommand ()
backward !Float
d = Float -> Turtle -> TurtleCommand ()
forward (-Float
d)

-- | Shorthand for `backward`.

bk :: Float -> Turtle -> TurtleCommand ()
bk :: Float -> Turtle -> TurtleCommand ()
bk = Float -> Turtle -> TurtleCommand ()
backward

calculateNewPointF_ :: P.Point -- ^ Starting point

                    -> Float -- ^ Distance

                    -> Float -- ^ Heading in degrees.

                    -> Float -- ^ coefficient [0, 1]

                    -> P.Point
calculateNewPointF_ :: Point -> Float -> Float -> Float -> Point
calculateNewPointF_ !Point
p !Float
d !Float
h !Float
q = Float -> Point -> Point -> Point
P.lerp Float
q Point
p Point
endP
  where !vec :: Point
vec = Float -> Point -> Point
P.rotateV (Float -> Float
P.degToRad Float
h) (Float
d, Float
0)
        !endP :: Point
endP = Point
vec Point -> Point -> Point
P.+ Point
p

-- | Move the turtle forward by the specified @distance@, in the direction the 

--   turtle is headed.

forward :: Float -- ^ Distance to move the turtle.

        -> Turtle -- ^ The turtle to move.

        -> TurtleCommand ()
forward :: Float -> Turtle -> TurtleCommand ()
forward !Float
d Turtle
turtle = ContT (AlmostVal ()) (TurtleState (AlmostVal ())) ()
-> TurtleCommand ()
forall a. SeqC a -> TurtleCommand a
TurtleCommand (ContT (AlmostVal ()) (TurtleState (AlmostVal ())) ()
 -> TurtleCommand ())
-> ContT (AlmostVal ()) (TurtleState (AlmostVal ())) ()
-> TurtleCommand ()
forall a b. (a -> b) -> a -> b
$ do
    TurtleData
t <- Turtle -> SeqC TurtleData
tData_ Turtle
turtle
    --  Get origin point

    Float
-> Float
-> (Float -> ContT (AlmostVal ()) (TurtleState (AlmostVal ())) ())
-> ContT (AlmostVal ()) (TurtleState (AlmostVal ())) ()
forall b a.
Float
-> Float -> (Float -> SequenceCommand b a) -> SequenceCommand b a
animate' Float
d (TurtleData
t TurtleData -> Getting Float TurtleData Float -> Float
forall s a. s -> Getting a s a -> a
^. Getting Float TurtleData Float
Lens' TurtleData Float
T.speed) ((Float -> ContT (AlmostVal ()) (TurtleState (AlmostVal ())) ())
 -> ContT (AlmostVal ()) (TurtleState (AlmostVal ())) ())
-> (Float -> ContT (AlmostVal ()) (TurtleState (AlmostVal ())) ())
-> ContT (AlmostVal ()) (TurtleState (AlmostVal ())) ()
forall a b. (a -> b) -> a -> b
$ \ Float
q -> do
      --  Get new endpoint via percentage

      let !startP :: Point
startP = TurtleData
t TurtleData -> Getting Point TurtleData Point -> Point
forall s a. s -> Getting a s a -> a
^. Getting Point TurtleData Point
Lens' TurtleData Point
T.position
      let !midP :: Point
midP = Point -> Float -> Float -> Float -> Point
calculateNewPointF_ Point
startP Float
d (TurtleData
t TurtleData -> Getting Float TurtleData Float -> Float
forall s a. s -> Getting a s a -> a
^. Getting Float TurtleData Float
Lens' TurtleData Float
T.heading) Float
q
      Bool
-> ContT (AlmostVal ()) (TurtleState (AlmostVal ())) ()
-> ContT (AlmostVal ()) (TurtleState (AlmostVal ())) ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (TurtleData
t TurtleData -> Getting Bool TurtleData Bool -> Bool
forall s a. s -> Getting a s a -> a
^. Getting Bool TurtleData Bool
Lens' TurtleData Bool
T.penDown) (ContT (AlmostVal ()) (TurtleState (AlmostVal ())) ()
 -> ContT (AlmostVal ()) (TurtleState (AlmostVal ())) ())
-> ContT (AlmostVal ()) (TurtleState (AlmostVal ())) ()
-> ContT (AlmostVal ()) (TurtleState (AlmostVal ())) ()
forall a b. (a -> b) -> a -> b
$ do -- don't draw if pen isn't in down state

        Picture -> ContT (AlmostVal ()) (TurtleState (AlmostVal ())) ()
forall b. Picture -> SequenceCommand b ()
addPicture (Picture -> ContT (AlmostVal ()) (TurtleState (AlmostVal ())) ())
-> Picture -> ContT (AlmostVal ()) (TurtleState (AlmostVal ())) ()
forall a b. (a -> b) -> a -> b
$ Color -> Picture -> Picture
color (TurtleData
t TurtleData -> Getting Color TurtleData Color -> Color
forall s a. s -> Getting a s a -> a
^. Getting Color TurtleData Color
Lens' TurtleData Color
T.penColor) 
                   (Picture -> Picture) -> Picture -> Picture
forall a b. (a -> b) -> a -> b
$ Point -> Point -> Float -> Picture
thickLine Point
startP Point
midP (TurtleData
t TurtleData -> Getting Float TurtleData Float -> Float
forall s a. s -> Getting a s a -> a
^. Getting Float TurtleData Float
Lens' TurtleData Float
T.penSize)
        --  Draw line from startPoint to midPoint.

      Turtle
-> (TurtleData -> Identity TurtleData)
-> TSC (AlmostVal ())
-> Identity (TSC (AlmostVal ()))
forall (f :: * -> *) b.
Applicative f =>
Turtle -> (TurtleData -> f TurtleData) -> TSC b -> f (TSC b)
turtLens_ Turtle
turtle ((TurtleData -> Identity TurtleData)
 -> TSC (AlmostVal ()) -> Identity (TSC (AlmostVal ())))
-> ((Point -> Identity Point) -> TurtleData -> Identity TurtleData)
-> (Point -> Identity Point)
-> TSC (AlmostVal ())
-> Identity (TSC (AlmostVal ()))
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Point -> Identity Point) -> TurtleData -> Identity TurtleData
Lens' TurtleData Point
T.position ((Point -> Identity Point)
 -> TSC (AlmostVal ()) -> Identity (TSC (AlmostVal ())))
-> Point -> ContT (AlmostVal ()) (TurtleState (AlmostVal ())) ()
forall s (m :: * -> *) a b.
MonadState s m =>
ASetter s s a b -> b -> m ()
.= Point
midP
      --  Update the turtle to a new position


-- | Shorthand for `forward`.

fd :: Float -> Turtle -> TurtleCommand ()
fd :: Float -> Turtle -> TurtleCommand ()
fd = Float -> Turtle -> TurtleCommand ()
forward

-- | Stamp a copy of the turtle shape onto the canvas at the current turtle 

--   position.

stamp :: Turtle -- ^ The turtle with the shape to be copied.

      -> TurtleCommand ()
stamp :: Turtle -> TurtleCommand ()
stamp Turtle
turtle = ContT (AlmostVal ()) (TurtleState (AlmostVal ())) ()
-> TurtleCommand ()
forall a. SeqC a -> TurtleCommand a
TurtleCommand (ContT (AlmostVal ()) (TurtleState (AlmostVal ())) ()
 -> TurtleCommand ())
-> ContT (AlmostVal ()) (TurtleState (AlmostVal ())) ()
-> TurtleCommand ()
forall a b. (a -> b) -> a -> b
$ Turtle -> SeqC TurtleData
tData_ Turtle
turtle SeqC TurtleData
-> (TurtleData
    -> ContT (AlmostVal ()) (TurtleState (AlmostVal ())) ())
-> ContT (AlmostVal ()) (TurtleState (AlmostVal ())) ()
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Picture -> ContT (AlmostVal ()) (TurtleState (AlmostVal ())) ()
forall b. Picture -> SequenceCommand b ()
addPicture (Picture -> ContT (AlmostVal ()) (TurtleState (AlmostVal ())) ())
-> (TurtleData -> Picture)
-> TurtleData
-> ContT (AlmostVal ()) (TurtleState (AlmostVal ())) ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. TurtleData -> Picture
T.drawTurtle 

-- | Turn a turtle right by the given degrees amount.

right :: Float -- ^ Rotation amount to apply to turtle.

      -> Turtle -- ^ The turtle to rotate.

      -> TurtleCommand ()
right :: Float -> Turtle -> TurtleCommand ()
right = Bool -> Float -> Turtle -> TurtleCommand ()
rotateTo_ Bool
True

-- | Shorthand for `right`.

rt :: Float -> Turtle -> TurtleCommand ()
rt :: Float -> Turtle -> TurtleCommand ()
rt = Float -> Turtle -> TurtleCommand ()
right

-- | Turn a turtle left by the given degrees amount.

left :: Float -- ^ Rotation amount to apply to turtle.

     -> Turtle -- ^ The turtle to rotate.

     -> TurtleCommand ()
left :: Float -> Turtle -> TurtleCommand ()
left = Bool -> Float -> Turtle -> TurtleCommand ()
rotateTo_ Bool
False

-- | Shorthand for `left`.

lt :: Float -> Turtle -> TurtleCommand ()
lt :: Float -> Turtle -> TurtleCommand ()
lt = Float -> Turtle -> TurtleCommand ()
left

rotateTo_ :: Bool -- ^ Bias decides in which direction rotation happens.

          -> Float -- ^ Amount to rotate by

          -> Turtle -- Turtle to modify.

          -> TurtleCommand ()
rotateTo_ :: Bool -> Float -> Turtle -> TurtleCommand ()
rotateTo_  Bool
rightBias !Float
r Turtle
turtle = ContT (AlmostVal ()) (TurtleState (AlmostVal ())) ()
-> TurtleCommand ()
forall a. SeqC a -> TurtleCommand a
TurtleCommand (ContT (AlmostVal ()) (TurtleState (AlmostVal ())) ()
 -> TurtleCommand ())
-> ContT (AlmostVal ()) (TurtleState (AlmostVal ())) ()
-> TurtleCommand ()
forall a b. (a -> b) -> a -> b
$ do
    TurtleData
t <- Turtle -> SeqC TurtleData
tData_ Turtle
turtle
    let r' :: Float
r' = Float -> Float
P.normalizeHeading Float
r
    Float
-> Float
-> (Float -> ContT (AlmostVal ()) (TurtleState (AlmostVal ())) ())
-> ContT (AlmostVal ()) (TurtleState (AlmostVal ())) ()
forall b a.
Float
-> Float -> (Float -> SequenceCommand b a) -> SequenceCommand b a
animate' (Float -> Float
P.degToRad Float
r') (TurtleData
t TurtleData -> Getting Float TurtleData Float -> Float
forall s a. s -> Getting a s a -> a
^. Getting Float TurtleData Float
Lens' TurtleData Float
T.rotationSpeed) ((Float -> ContT (AlmostVal ()) (TurtleState (AlmostVal ())) ())
 -> ContT (AlmostVal ()) (TurtleState (AlmostVal ())) ())
-> (Float -> ContT (AlmostVal ()) (TurtleState (AlmostVal ())) ())
-> ContT (AlmostVal ()) (TurtleState (AlmostVal ())) ()
forall a b. (a -> b) -> a -> b
$ \Float
q -> do
      let !h :: Float
h = TurtleData
t TurtleData -> Getting Float TurtleData Float -> Float
forall s a. s -> Getting a s a -> a
^. Getting Float TurtleData Float
Lens' TurtleData Float
T.heading
      let !newHeading :: Float
newHeading = Float -> Float
P.normalizeHeading (Float -> Float) -> Float -> Float
forall a b. (a -> b) -> a -> b
$ if Bool
rightBias then Float
h Float -> Float -> Float
forall a. Num a => a -> a -> a
- Float
q Float -> Float -> Float
forall a. Num a => a -> a -> a
* Float
r'
                                                          else Float
h Float -> Float -> Float
forall a. Num a => a -> a -> a
+ Float
q Float -> Float -> Float
forall a. Num a => a -> a -> a
* Float
r'
      --  Get new heading via percentage

      Turtle
-> (TurtleData -> Identity TurtleData)
-> TSC (AlmostVal ())
-> Identity (TSC (AlmostVal ()))
forall (f :: * -> *) b.
Applicative f =>
Turtle -> (TurtleData -> f TurtleData) -> TSC b -> f (TSC b)
turtLens_ Turtle
turtle ((TurtleData -> Identity TurtleData)
 -> TSC (AlmostVal ()) -> Identity (TSC (AlmostVal ())))
-> ((Float -> Identity Float) -> TurtleData -> Identity TurtleData)
-> (Float -> Identity Float)
-> TSC (AlmostVal ())
-> Identity (TSC (AlmostVal ()))
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Float -> Identity Float) -> TurtleData -> Identity TurtleData
Lens' TurtleData Float
T.heading ((Float -> Identity Float)
 -> TSC (AlmostVal ()) -> Identity (TSC (AlmostVal ())))
-> Float -> ContT (AlmostVal ()) (TurtleState (AlmostVal ())) ()
forall s (m :: * -> *) a b.
MonadState s m =>
ASetter s s a b -> b -> m ()
.= Float
newHeading

-- | Draws an arc starting from a given starting point on the edge of the

--   circle.

drawCircle_ :: P.Point -- ^ Point on edge of circle to start from

            -> Float -- ^ Radius of circle

            -> Float -- ^ Absolute starting angle in degrees

            -> Float -- ^ Rotation amount about radius in degrees

            -> Float -- ^ Line thickness (penSize)

            -> Color -- ^ Color of circle 

            -> Picture -- ^ Resulting circle

drawCircle_ :: Point -> Float -> Float -> Float -> Float -> Color -> Picture
drawCircle_ !Point
p !Float
radius !Float
startAngle !Float
endAngle !Float
pSize !Color
pColor = 
 Float -> Float -> Picture -> Picture
translate (Point -> Float
forall a b. (a, b) -> a
fst Point
p) (Point -> Float
forall a b. (a, b) -> b
snd Point
p) (Picture -> Picture) -> Picture -> Picture
forall a b. (a -> b) -> a -> b
$ Float -> Picture -> Picture
rotate (Float
180 Float -> Float -> Float
forall a. Num a => a -> a -> a
- Float
startAngle)
                           (Picture -> Picture) -> Picture -> Picture
forall a b. (a -> b) -> a -> b
$ Float -> Float -> Picture -> Picture
translate (-Float
radius) Float
0
                           (Picture -> Picture) -> Picture -> Picture
forall a b. (a -> b) -> a -> b
$ Color -> Picture -> Picture
color Color
pColor
                           (Picture -> Picture) -> Picture -> Picture
forall a b. (a -> b) -> a -> b
$ Float -> Float -> Picture -> Picture
scale (if Float
radius Float -> Float -> Bool
forall a. Ord a => a -> a -> Bool
>= Float
0 then Float
1 else -Float
1) Float
1
                           (Picture -> Picture) -> Picture -> Picture
forall a b. (a -> b) -> a -> b
$ Float -> Float -> Float -> Float -> Picture
thickArc Float
0 (Float
endAngle) (Float -> Float
forall a. Num a => a -> a
abs Float
radius) Float
pSize

-- Calculates the next position of a turtle on a circle.

calculateNewPointC_ :: P.Point -- ^ Point on edge of circle

                    -> Float -- ^ Radius of circle

                    -> Float -- ^ Absolute starting angle in degrees

                    -> Float -- ^ Rotation amount about radius in degrees

                    -> P.Point -- ^ Resulting new point

calculateNewPointC_ :: Point -> Float -> Float -> Float -> Point
calculateNewPointC_ !Point
p !Float
radius !Float
startAngle !Float
angle = (Float
px, Float
py)
  where !px :: Float
px = Point -> Float
forall a b. (a, b) -> a
fst Point
p Float -> Float -> Float
forall a. Num a => a -> a -> a
- (Float
radius Float -> Float -> Float
forall a. Num a => a -> a -> a
* (Float -> Float
forall a. Floating a => a -> a
cos Float
a Float -> Float -> Float
forall a. Num a => a -> a -> a
- Float -> Float
forall a. Floating a => a -> a
cos Float
s))
        !py :: Float
py = Point -> Float
forall a b. (a, b) -> b
snd Point
p Float -> Float -> Float
forall a. Num a => a -> a -> a
- (Float
radius Float -> Float -> Float
forall a. Num a => a -> a -> a
* (Float -> Float
forall a. Floating a => a -> a
sin Float
a Float -> Float -> Float
forall a. Num a => a -> a -> a
- Float -> Float
forall a. Floating a => a -> a
sin Float
s))
        !s :: Float
s = Float -> Float
P.degToRad Float
startAngle
        !a :: Float
a = Float -> Float
P.degToRad (Float -> Float) -> Float -> Float
forall a b. (a -> b) -> a -> b
$ if Float
radius Float -> Float -> Bool
forall a. Ord a => a -> a -> Bool
>= Float
0 then Float
startAngle Float -> Float -> Float
forall a. Num a => a -> a -> a
+ Float
angle
                                         else Float
startAngle Float -> Float -> Float
forall a. Num a => a -> a -> a
- Float
angle

-- | Draw an arc with a given @radius@. The center is @radius@ units left of the

--   @turtle@ if positive. Otherwise  @radius@ units right of the @turtle@ if 

--   negative.

--

--   The arc is drawn in an anticlockwise direction if the radius is positive,

--   otherwise, it is drawn in a clockwise direction.

circle  :: Float -- ^ Radius of the circle.

        -> Float -- ^ Angle to travel in degrees. 

                 -- For example: @360@ for a full circle or @180@ for a 

                 -- semicircle.

        -> Turtle -- ^ Turtle to move in a circle.

        -> TurtleCommand ()
circle :: Float -> Float -> Turtle -> TurtleCommand ()
circle !Float
radius !Float
r Turtle
turtle = ContT (AlmostVal ()) (TurtleState (AlmostVal ())) ()
-> TurtleCommand ()
forall a. SeqC a -> TurtleCommand a
TurtleCommand (ContT (AlmostVal ()) (TurtleState (AlmostVal ())) ()
 -> TurtleCommand ())
-> ContT (AlmostVal ()) (TurtleState (AlmostVal ())) ()
-> TurtleCommand ()
forall a b. (a -> b) -> a -> b
$ do
  TurtleData
t <- Turtle -> SeqC TurtleData
tData_ Turtle
turtle
  let !r' :: Float
r' = Float -> Float
P.normalizeHeading Float
r
  Float
-> Float
-> (Float -> ContT (AlmostVal ()) (TurtleState (AlmostVal ())) ())
-> ContT (AlmostVal ()) (TurtleState (AlmostVal ())) ()
forall b a.
Float
-> Float -> (Float -> SequenceCommand b a) -> SequenceCommand b a
animate' (Float -> Float
forall a. Num a => a -> a
abs Float
radius Float -> Float -> Float
forall a. Num a => a -> a -> a
* Float -> Float
P.degToRad Float
r') (TurtleData
t TurtleData -> Getting Float TurtleData Float -> Float
forall s a. s -> Getting a s a -> a
^. Getting Float TurtleData Float
Lens' TurtleData Float
T.speed) ((Float -> ContT (AlmostVal ()) (TurtleState (AlmostVal ())) ())
 -> ContT (AlmostVal ()) (TurtleState (AlmostVal ())) ())
-> (Float -> ContT (AlmostVal ()) (TurtleState (AlmostVal ())) ())
-> ContT (AlmostVal ()) (TurtleState (AlmostVal ())) ()
forall a b. (a -> b) -> a -> b
$ \ Float
q -> do
    let !startAngle :: Float
startAngle = TurtleData
t TurtleData -> Getting Float TurtleData Float -> Float
forall s a. s -> Getting a s a -> a
^. Getting Float TurtleData Float
Lens' TurtleData Float
T.heading Float -> Float -> Float
forall a. Num a => a -> a -> a
+ Float
90
    let !p :: Point
p = TurtleData
t TurtleData -> Getting Point TurtleData Point -> Point
forall s a. s -> Getting a s a -> a
^. Getting Point TurtleData Point
Lens' TurtleData Point
T.position
    let !angle :: Float
angle = Float
r' Float -> Float -> Float
forall a. Num a => a -> a -> a
* Float
q
    Bool
-> ContT (AlmostVal ()) (TurtleState (AlmostVal ())) ()
-> ContT (AlmostVal ()) (TurtleState (AlmostVal ())) ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (TurtleData
t TurtleData -> Getting Bool TurtleData Bool -> Bool
forall s a. s -> Getting a s a -> a
^. Getting Bool TurtleData Bool
Lens' TurtleData Bool
T.penDown) (ContT (AlmostVal ()) (TurtleState (AlmostVal ())) ()
 -> ContT (AlmostVal ()) (TurtleState (AlmostVal ())) ())
-> ContT (AlmostVal ()) (TurtleState (AlmostVal ())) ()
-> ContT (AlmostVal ()) (TurtleState (AlmostVal ())) ()
forall a b. (a -> b) -> a -> b
$ do -- don't draw if pen isn't in down state

      Picture -> ContT (AlmostVal ()) (TurtleState (AlmostVal ())) ()
forall b. Picture -> SequenceCommand b ()
addPicture (Picture -> ContT (AlmostVal ()) (TurtleState (AlmostVal ())) ())
-> Picture -> ContT (AlmostVal ()) (TurtleState (AlmostVal ())) ()
forall a b. (a -> b) -> a -> b
$! Point -> Float -> Float -> Float -> Float -> Color -> Picture
drawCircle_ Point
p Float
radius Float
startAngle Float
angle 
                    (TurtleData
t TurtleData -> Getting Float TurtleData Float -> Float
forall s a. s -> Getting a s a -> a
^. Getting Float TurtleData Float
Lens' TurtleData Float
T.penSize) (TurtleData
t TurtleData -> Getting Color TurtleData Color -> Color
forall s a. s -> Getting a s a -> a
^. Getting Color TurtleData Color
Lens' TurtleData Color
T.penColor)

    -- Update the turtle with the new values.

    let ts :: (TurtleData -> Identity TurtleData) -> TSC b -> Identity (TSC b)
ts = Turtle
-> (TurtleData -> Identity TurtleData) -> TSC b -> Identity (TSC b)
forall (f :: * -> *) b.
Applicative f =>
Turtle -> (TurtleData -> f TurtleData) -> TSC b -> f (TSC b)
turtLens_ Turtle
turtle
    (TurtleData -> Identity TurtleData)
-> TSC (AlmostVal ()) -> Identity (TSC (AlmostVal ()))
forall b.
(TurtleData -> Identity TurtleData) -> TSC b -> Identity (TSC b)
ts ((TurtleData -> Identity TurtleData)
 -> TSC (AlmostVal ()) -> Identity (TSC (AlmostVal ())))
-> ((Float -> Identity Float) -> TurtleData -> Identity TurtleData)
-> (Float -> Identity Float)
-> TSC (AlmostVal ())
-> Identity (TSC (AlmostVal ()))
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Float -> Identity Float) -> TurtleData -> Identity TurtleData
Lens' TurtleData Float
T.heading ((Float -> Identity Float)
 -> TSC (AlmostVal ()) -> Identity (TSC (AlmostVal ())))
-> Float -> ContT (AlmostVal ()) (TurtleState (AlmostVal ())) ()
forall s (m :: * -> *) a b.
MonadState s m =>
ASetter s s a b -> b -> m ()
.= Float -> Float
P.normalizeHeading (if Float
radius Float -> Float -> Bool
forall a. Ord a => a -> a -> Bool
>= Float
0
                                          then Float
startAngle Float -> Float -> Float
forall a. Num a => a -> a -> a
- Float
90 Float -> Float -> Float
forall a. Num a => a -> a -> a
+ Float
angle
                                          else Float
startAngle Float -> Float -> Float
forall a. Num a => a -> a -> a
- Float
90 Float -> Float -> Float
forall a. Num a => a -> a -> a
- Float
angle)
    

    let !p' :: Point
p' = Point -> Float -> Float -> Float -> Point
calculateNewPointC_ Point
p Float
radius Float
startAngle Float
angle
    (TurtleData -> Identity TurtleData)
-> TSC (AlmostVal ()) -> Identity (TSC (AlmostVal ()))
forall b.
(TurtleData -> Identity TurtleData) -> TSC b -> Identity (TSC b)
ts ((TurtleData -> Identity TurtleData)
 -> TSC (AlmostVal ()) -> Identity (TSC (AlmostVal ())))
-> ((Point -> Identity Point) -> TurtleData -> Identity TurtleData)
-> (Point -> Identity Point)
-> TSC (AlmostVal ())
-> Identity (TSC (AlmostVal ()))
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Point -> Identity Point) -> TurtleData -> Identity TurtleData
Lens' TurtleData Point
T.position ((Point -> Identity Point)
 -> TSC (AlmostVal ()) -> Identity (TSC (AlmostVal ())))
-> Point -> ContT (AlmostVal ()) (TurtleState (AlmostVal ())) ()
forall s (m :: * -> *) a b.
MonadState s m =>
ASetter s s a b -> b -> m ()
.= Point
p'

-- | Returns the turtle's current position.

--   Default (starting) position is @(0, 0)@.

position :: Turtle -- ^ Turtle to query.

         -> TurtleCommand P.Point -- ^ Returned current point.

position :: Turtle -> TurtleCommand Point
position = Point -> Lens' TurtleData Point -> Turtle -> TurtleCommand Point
forall a. a -> Lens' TurtleData a -> Turtle -> TurtleCommand a
getter_ (Float
0, Float
0) Lens' TurtleData Point
T.position

-- | Warps the turtle to its starting position @(0, 0)@ and resets the

-- orientation to @North@ (90 degrees). No line is drawn moving the turtle.

home :: Turtle
     -> TurtleCommand ()
home :: Turtle -> TurtleCommand ()
home Turtle
turtle = ContT (AlmostVal ()) (TurtleState (AlmostVal ())) ()
-> TurtleCommand ()
forall a. SeqC a -> TurtleCommand a
TurtleCommand (ContT (AlmostVal ()) (TurtleState (AlmostVal ())) ()
 -> TurtleCommand ())
-> ContT (AlmostVal ()) (TurtleState (AlmostVal ())) ()
-> TurtleCommand ()
forall a b. (a -> b) -> a -> b
$ do
  let ts :: (TurtleData -> Identity TurtleData) -> TSC b -> Identity (TSC b)
ts = Turtle
-> (TurtleData -> Identity TurtleData) -> TSC b -> Identity (TSC b)
forall (f :: * -> *) b.
Applicative f =>
Turtle -> (TurtleData -> f TurtleData) -> TSC b -> f (TSC b)
turtLens_ Turtle
turtle
  (TurtleData -> Identity TurtleData)
-> TSC (AlmostVal ()) -> Identity (TSC (AlmostVal ()))
forall b.
(TurtleData -> Identity TurtleData) -> TSC b -> Identity (TSC b)
ts ((TurtleData -> Identity TurtleData)
 -> TSC (AlmostVal ()) -> Identity (TSC (AlmostVal ())))
-> ((Point -> Identity Point) -> TurtleData -> Identity TurtleData)
-> (Point -> Identity Point)
-> TSC (AlmostVal ())
-> Identity (TSC (AlmostVal ()))
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Point -> Identity Point) -> TurtleData -> Identity TurtleData
Lens' TurtleData Point
T.position       ((Point -> Identity Point)
 -> TSC (AlmostVal ()) -> Identity (TSC (AlmostVal ())))
-> Point -> ContT (AlmostVal ()) (TurtleState (AlmostVal ())) ()
forall s (m :: * -> *) a b.
MonadState s m =>
ASetter s s a b -> b -> m ()
.= (Float
0, Float
0)
  (TurtleData -> Identity TurtleData)
-> TSC (AlmostVal ()) -> Identity (TSC (AlmostVal ()))
forall b.
(TurtleData -> Identity TurtleData) -> TSC b -> Identity (TSC b)
ts ((TurtleData -> Identity TurtleData)
 -> TSC (AlmostVal ()) -> Identity (TSC (AlmostVal ())))
-> ((Float -> Identity Float) -> TurtleData -> Identity TurtleData)
-> (Float -> Identity Float)
-> TSC (AlmostVal ())
-> Identity (TSC (AlmostVal ()))
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Float -> Identity Float) -> TurtleData -> Identity TurtleData
Lens' TurtleData Float
T.heading        ((Float -> Identity Float)
 -> TSC (AlmostVal ()) -> Identity (TSC (AlmostVal ())))
-> Float -> ContT (AlmostVal ()) (TurtleState (AlmostVal ())) ()
forall s (m :: * -> *) a b.
MonadState s m =>
ASetter s s a b -> b -> m ()
.= Float
90

-- | Warps the turtle to a new position.

--   The turtle jumps to this new position with no animation. If the pen is down

--   then a line is drawn.

--   

--   This does not affect the turtle's heading.

goto :: P.Point -- ^ Position to warp to.

     -> Turtle -- ^ Turtle to modify.

     -> TurtleCommand ()
goto :: Point -> Turtle -> TurtleCommand ()
goto Point
point Turtle
turtle = ContT (AlmostVal ()) (TurtleState (AlmostVal ())) ()
-> TurtleCommand ()
forall a. SeqC a -> TurtleCommand a
TurtleCommand (ContT (AlmostVal ()) (TurtleState (AlmostVal ())) ()
 -> TurtleCommand ())
-> ContT (AlmostVal ()) (TurtleState (AlmostVal ())) ()
-> TurtleCommand ()
forall a b. (a -> b) -> a -> b
$ do
  TurtleData
t <- Turtle -> SeqC TurtleData
tData_ Turtle
turtle
  let startP :: Point
startP = TurtleData
t TurtleData -> Getting Point TurtleData Point -> Point
forall s a. s -> Getting a s a -> a
^. Getting Point TurtleData Point
Lens' TurtleData Point
T.position
  Bool
-> ContT (AlmostVal ()) (TurtleState (AlmostVal ())) ()
-> ContT (AlmostVal ()) (TurtleState (AlmostVal ())) ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (TurtleData
t TurtleData -> Getting Bool TurtleData Bool -> Bool
forall s a. s -> Getting a s a -> a
^. Getting Bool TurtleData Bool
Lens' TurtleData Bool
T.penDown) (ContT (AlmostVal ()) (TurtleState (AlmostVal ())) ()
 -> ContT (AlmostVal ()) (TurtleState (AlmostVal ())) ())
-> ContT (AlmostVal ()) (TurtleState (AlmostVal ())) ()
-> ContT (AlmostVal ()) (TurtleState (AlmostVal ())) ()
forall a b. (a -> b) -> a -> b
$ Picture -> ContT (AlmostVal ()) (TurtleState (AlmostVal ())) ()
forall b. Picture -> SequenceCommand b ()
addPicture 
                        (Picture -> ContT (AlmostVal ()) (TurtleState (AlmostVal ())) ())
-> Picture -> ContT (AlmostVal ()) (TurtleState (AlmostVal ())) ()
forall a b. (a -> b) -> a -> b
$ Color -> Picture -> Picture
color (TurtleData
t TurtleData -> Getting Color TurtleData Color -> Color
forall s a. s -> Getting a s a -> a
^. Getting Color TurtleData Color
Lens' TurtleData Color
T.penColor) 
                        (Picture -> Picture) -> Picture -> Picture
forall a b. (a -> b) -> a -> b
$ Point -> Point -> Float -> Picture
thickLine Point
startP Point
point (TurtleData
t TurtleData -> Getting Float TurtleData Float -> Float
forall s a. s -> Getting a s a -> a
^. Getting Float TurtleData Float
Lens' TurtleData Float
T.penSize)
  Turtle
-> (TurtleData -> Identity TurtleData)
-> TSC (AlmostVal ())
-> Identity (TSC (AlmostVal ()))
forall (f :: * -> *) b.
Applicative f =>
Turtle -> (TurtleData -> f TurtleData) -> TSC b -> f (TSC b)
turtLens_ Turtle
turtle ((TurtleData -> Identity TurtleData)
 -> TSC (AlmostVal ()) -> Identity (TSC (AlmostVal ())))
-> ((Point -> Identity Point) -> TurtleData -> Identity TurtleData)
-> (Point -> Identity Point)
-> TSC (AlmostVal ())
-> Identity (TSC (AlmostVal ()))
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Point -> Identity Point) -> TurtleData -> Identity TurtleData
Lens' TurtleData Point
T.position ((Point -> Identity Point)
 -> TSC (AlmostVal ()) -> Identity (TSC (AlmostVal ())))
-> Point -> ContT (AlmostVal ()) (TurtleState (AlmostVal ())) ()
forall s (m :: * -> *) a b.
MonadState s m =>
ASetter s s a b -> b -> m ()
.= Point
point

-- | Alias of `goto`.

setPosition :: P.Point -> Turtle -> TurtleCommand ()
setPosition :: Point -> Turtle -> TurtleCommand ()
setPosition = Point -> Turtle -> TurtleCommand ()
goto

-- | Returns the turtle's heading.

--   

--   @0@ is along the positive x-axis, going anticlockwise. So:

--

--   * East is @0@ degrees.

--   * North is @90@ degrees.

--   * West is @180@ degrees.

--   * South is @270@ degrees.

--

--   The default heading is North (@90@ degrees).

heading :: Turtle -- ^ Turtle to query.

         -> TurtleCommand Float -- ^ Returned heading as angle in degrees.

heading :: Turtle -> TurtleCommand Float
heading = Float -> Lens' TurtleData Float -> Turtle -> TurtleCommand Float
forall a. a -> Lens' TurtleData a -> Turtle -> TurtleCommand a
getter_ Float
0 Lens' TurtleData Float
T.heading

-- | Sets the turtle's heading. See `heading`.

setHeading :: Float -- ^ Heading to apply. 

           -> Turtle -- ^ Turtle to modify.

           -> TurtleCommand ()
setHeading :: Float -> Turtle -> TurtleCommand ()
setHeading = Lens' TurtleData Float -> Float -> Turtle -> TurtleCommand ()
forall b. Lens' TurtleData b -> b -> Turtle -> TurtleCommand ()
setter_ Lens' TurtleData Float
T.heading

-- | Returns the turtle's pen color.

--   The color of the turtle's pen.The default color is @black@.

penColor :: Turtle -- ^ Turtle to query.

         -> TurtleCommand Color -- ^ Returned current pen color.

penColor :: Turtle -> TurtleCommand Color
penColor = Color -> Lens' TurtleData Color -> Turtle -> TurtleCommand Color
forall a. a -> Lens' TurtleData a -> Turtle -> TurtleCommand a
getter_ Color
black Lens' TurtleData Color
T.penColor

-- | Set the turtle's pen color.

--  See `penColor`.

setPenColor :: Color -- ^ New pen color to apply

            -> Turtle -- ^ Turtle to modify.

            -> TurtleCommand ()
setPenColor :: Color -> Turtle -> TurtleCommand ()
setPenColor = Lens' TurtleData Color -> Color -> Turtle -> TurtleCommand ()
forall b. Lens' TurtleData b -> b -> Turtle -> TurtleCommand ()
setter_ Lens' TurtleData Color
T.penColor

-- | Returns whether the turtle's pen is down.

--   When the turtle's pen is down it will draw a line when it moves.

--   The default value is @True@.

penDown :: Turtle -- ^ Turtle to query.

         -> TurtleCommand Bool -- ^ True if pen is down, false if not.

penDown :: Turtle -> TurtleCommand Bool
penDown = Bool -> Lens' TurtleData Bool -> Turtle -> TurtleCommand Bool
forall a. a -> Lens' TurtleData a -> Turtle -> TurtleCommand a
getter_ Bool
False Lens' TurtleData Bool
T.penDown

-- | Sets the turtle's pen to down or up.

--   See `penDown`.

setPenDown :: Bool -- ^ New state for pen flag. True for down. False for up.

           -> Turtle -- ^ Turtle to modify.

           -> TurtleCommand ()
setPenDown :: Bool -> Turtle -> TurtleCommand ()
setPenDown = Lens' TurtleData Bool -> Bool -> Turtle -> TurtleCommand ()
forall b. Lens' TurtleData b -> b -> Turtle -> TurtleCommand ()
setter_ Lens' TurtleData Bool
T.penDown

-- | Returns the turtle's pen size.

--   Defaults to @2@.

penSize :: Turtle -- ^ Turtle to query.

         -> TurtleCommand Float -- ^ Size of turtle's pen.

penSize :: Turtle -> TurtleCommand Float
penSize = Float -> Lens' TurtleData Float -> Turtle -> TurtleCommand Float
forall a. a -> Lens' TurtleData a -> Turtle -> TurtleCommand a
getter_ Float
0 Lens' TurtleData Float
T.penSize

-- | Sets the turtle's pen size.

--   See `penSize`.

setPenSize :: Float -- ^ New size for turtle's pen.

           -> Turtle -- ^ Turtle to modify.

           -> TurtleCommand ()
setPenSize :: Float -> Turtle -> TurtleCommand ()
setPenSize = Lens' TurtleData Float -> Float -> Turtle -> TurtleCommand ()
forall b. Lens' TurtleData b -> b -> Turtle -> TurtleCommand ()
setter_ Lens' TurtleData Float
T.penSize

-- | Returns whether the turtle is visible.

--   The default value is @True@.

visible :: Turtle -- ^ Turtle to query.

        -> TurtleCommand Bool -- ^ @True@ if turtle is visible, @False@ if not.

visible :: Turtle -> TurtleCommand Bool
visible = Bool -> Lens' TurtleData Bool -> Turtle -> TurtleCommand Bool
forall a. a -> Lens' TurtleData a -> Turtle -> TurtleCommand a
getter_ Bool
False Lens' TurtleData Bool
T.visible

-- | Sets the turtle's visibility.

--   See `visible`.

setVisible :: Bool -- ^ New state for visible flag.

           -> Turtle -- ^ Turtle to modify.

           -> TurtleCommand ()
setVisible :: Bool -> Turtle -> TurtleCommand ()
setVisible = Lens' TurtleData Bool -> Bool -> Turtle -> TurtleCommand ()
forall b. Lens' TurtleData b -> b -> Turtle -> TurtleCommand ()
setter_ Lens' TurtleData Bool
T.visible

-- | Returns the turtle's current speed.

--   Speed is is @distance@ per second.

--   A speed of 0 is equivalent to no animation being performed and instant 

--   movement.

-- The default value is @200@.

speed :: Turtle -- ^ Turtle to query.

      -> TurtleCommand Float -- ^ Speed of turtle.

speed :: Turtle -> TurtleCommand Float
speed = Float -> Lens' TurtleData Float -> Turtle -> TurtleCommand Float
forall a. a -> Lens' TurtleData a -> Turtle -> TurtleCommand a
getter_ Float
0 Lens' TurtleData Float
T.speed

-- | Sets the turtle's speed.

--   See `speed`.

setSpeed :: Float -- ^ New speed.

         -> Turtle -- ^ Turtle to modify.

         -> TurtleCommand ()
setSpeed :: Float -> Turtle -> TurtleCommand ()
setSpeed = Lens' TurtleData Float -> Float -> Turtle -> TurtleCommand ()
forall b. Lens' TurtleData b -> b -> Turtle -> TurtleCommand ()
setter_ Lens' TurtleData Float
T.speed

-- | Returns the turtle's current rotation speed.

--   Rotation speed is is the speed in seconds it takes to do a full revolution.

--   A speed of 0 is equivalent to no animation being performed and instant 

--   rotation.

-- The default value is @20@.

rotationSpeed :: Turtle -- ^ Turtle to query.

              -> TurtleCommand Float -- ^ Rotation speed of turtle.

rotationSpeed :: Turtle -> TurtleCommand Float
rotationSpeed = Float -> Lens' TurtleData Float -> Turtle -> TurtleCommand Float
forall a. a -> Lens' TurtleData a -> Turtle -> TurtleCommand a
getter_ Float
0 Lens' TurtleData Float
T.rotationSpeed

-- | Sets the turtle's rotation speed.

--   See `rotationSpeed`.

setRotationSpeed :: Float -- ^ New rotation speed.

                 -> Turtle -- ^ Turtle to modify.

                 -> TurtleCommand ()
setRotationSpeed :: Float -> Turtle -> TurtleCommand ()
setRotationSpeed = Lens' TurtleData Float -> Float -> Turtle -> TurtleCommand ()
forall b. Lens' TurtleData b -> b -> Turtle -> TurtleCommand ()
setter_ Lens' TurtleData Float
T.rotationSpeed

-- | Gets the turtle's representation as a `Picture`.

representation :: Turtle -- ^ Turtle to query.

               -> TurtleCommand Picture
representation :: Turtle -> TurtleCommand Picture
representation = Picture
-> Lens' TurtleData Picture -> Turtle -> TurtleCommand Picture
forall a. a -> Lens' TurtleData a -> Turtle -> TurtleCommand a
getter_ Picture
blank Lens' TurtleData Picture
T.representation

{- | Sets the turtle's representation to a `Picture`.
   See `representation`.
   For example, to set the turtle as a red circle:
   
   @
    import Graphics.WorldTurtle
    import qualified Graphics.Gloss.Data.Picture as G

    myCommand :: TurtleCommand ()
    myCommand = do
      t <- makeTurtle
      setPenColor red t
      setRepresentation (G.color red $ G.circleSolid 10) t
      forward 90 t
   @
-}
setRepresentation :: Picture -- ^ Picture to apply.

                  -> Turtle -- ^ Turtle to modify.

                  -> TurtleCommand ()
setRepresentation :: Picture -> Turtle -> TurtleCommand ()
setRepresentation = Lens' TurtleData Picture -> Picture -> Turtle -> TurtleCommand ()
forall b. Lens' TurtleData b -> b -> Turtle -> TurtleCommand ()
setter_ Lens' TurtleData Picture
T.representation

-- | Clears all drawings form the canvas. Does not alter any turtle's state.

clear :: TurtleCommand ()
clear :: TurtleCommand ()
clear = ContT (AlmostVal ()) (TurtleState (AlmostVal ())) ()
-> TurtleCommand ()
forall a. SeqC a -> TurtleCommand a
TurtleCommand (ContT (AlmostVal ()) (TurtleState (AlmostVal ())) ()
 -> TurtleCommand ())
-> ContT (AlmostVal ()) (TurtleState (AlmostVal ())) ()
-> TurtleCommand ()
forall a b. (a -> b) -> a -> b
$ ([Picture] -> Identity [Picture])
-> TSC (AlmostVal ()) -> Identity (TSC (AlmostVal ()))
forall b. Lens' (TSC b) [Picture]
pics (([Picture] -> Identity [Picture])
 -> TSC (AlmostVal ()) -> Identity (TSC (AlmostVal ())))
-> [Picture]
-> ContT (AlmostVal ()) (TurtleState (AlmostVal ())) ()
forall s (m :: * -> *) a b.
MonadState s m =>
ASetter s s a b -> b -> m ()
.= []

-- | Sleep for a given amount of time in seconds. When sleeping no animation 

--   runs. A negative value will be clamped to @0@.

sleep :: Float -> TurtleCommand ()
sleep :: Float -> TurtleCommand ()
sleep = ContT (AlmostVal ()) (TurtleState (AlmostVal ())) ()
-> TurtleCommand ()
forall a. SeqC a -> TurtleCommand a
TurtleCommand (ContT (AlmostVal ()) (TurtleState (AlmostVal ())) ()
 -> TurtleCommand ())
-> (Float -> ContT (AlmostVal ()) (TurtleState (AlmostVal ())) ())
-> Float
-> TurtleCommand ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Float -> ContT (AlmostVal ()) (TurtleState (AlmostVal ())) ()
forall b. Float -> SequenceCommand b ()
decrementSimTime (Float -> ContT (AlmostVal ()) (TurtleState (AlmostVal ())) ())
-> (Float -> Float)
-> Float
-> ContT (AlmostVal ()) (TurtleState (AlmostVal ())) ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Float -> Float -> Float
forall a. Ord a => a -> a -> a
max Float
0

-- | @90@ degrees.

north :: Float
north :: Float
north = Float
90

-- | @0@ degrees.

east :: Float
east :: Float
east = Float
0

-- | @180@ degrees.

west :: Float 
west :: Float
west = Float
180

-- | @270@ degrees.

south :: Float
south :: Float
south = Float
270

{-
   Here be dirty helper functions:
-}

-- | Looks up the turtle data for the given turtle in the state monad.

-- This type signature comes form GHC...my prism-foo is not good enough to sugar it.

turtLens_ :: Applicative f 
          => Turtle 
          -> (T.TurtleData -> f T.TurtleData) 
          -> TSC b 
          -> f (TSC b) 
turtLens_ :: Turtle -> (TurtleData -> f TurtleData) -> TSC b -> f (TSC b)
turtLens_ Turtle
t = (Map Turtle TurtleData -> f (Map Turtle TurtleData))
-> TSC b -> f (TSC b)
forall b. Lens' (TSC b) (Map Turtle TurtleData)
turtles ((Map Turtle TurtleData -> f (Map Turtle TurtleData))
 -> TSC b -> f (TSC b))
-> ((TurtleData -> f TurtleData)
    -> Map Turtle TurtleData -> f (Map Turtle TurtleData))
-> (TurtleData -> f TurtleData)
-> TSC b
-> f (TSC b)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Index (Map Turtle TurtleData)
-> Lens'
     (Map Turtle TurtleData) (Maybe (IxValue (Map Turtle TurtleData)))
forall m. At m => Index m -> Lens' m (Maybe (IxValue m))
at Index (Map Turtle TurtleData)
Turtle
t ((Maybe TurtleData -> f (Maybe TurtleData))
 -> Map Turtle TurtleData -> f (Map Turtle TurtleData))
-> ((TurtleData -> f TurtleData)
    -> Maybe TurtleData -> f (Maybe TurtleData))
-> (TurtleData -> f TurtleData)
-> Map Turtle TurtleData
-> f (Map Turtle TurtleData)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (TurtleData -> f TurtleData)
-> Maybe TurtleData -> f (Maybe TurtleData)
forall a b. Prism (Maybe a) (Maybe b) a b
_Just
{-# INLINE turtLens_ #-}

-- | This is a helper function for our getter commands.

--   It takes a default value, the lense to compose, and the turtle to inspect.

getter_ :: a -> Lens' T.TurtleData a -> Turtle -> TurtleCommand a
getter_ :: a -> Lens' TurtleData a -> Turtle -> TurtleCommand a
getter_ a
def Lens' TurtleData a
l Turtle
t = 
  SeqC a -> TurtleCommand a
forall a. SeqC a -> TurtleCommand a
TurtleCommand (SeqC a -> TurtleCommand a) -> SeqC a -> TurtleCommand a
forall a b. (a -> b) -> a -> b
$ a -> Maybe a -> a
forall a. a -> Maybe a -> a
fromMaybe a
def (Maybe a -> a)
-> ContT (AlmostVal ()) (TurtleState (AlmostVal ())) (Maybe a)
-> SeqC a
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Getting (First a) (TSC (AlmostVal ())) a
-> ContT (AlmostVal ()) (TurtleState (AlmostVal ())) (Maybe a)
forall s (m :: * -> *) a.
MonadState s m =>
Getting (First a) s a -> m (Maybe a)
preuse (Turtle
-> (TurtleData -> Const (First a) TurtleData)
-> TSC (AlmostVal ())
-> Const (First a) (TSC (AlmostVal ()))
forall (f :: * -> *) b.
Applicative f =>
Turtle -> (TurtleData -> f TurtleData) -> TSC b -> f (TSC b)
turtLens_ Turtle
t ((TurtleData -> Const (First a) TurtleData)
 -> TSC (AlmostVal ()) -> Const (First a) (TSC (AlmostVal ())))
-> ((a -> Const (First a) a)
    -> TurtleData -> Const (First a) TurtleData)
-> Getting (First a) (TSC (AlmostVal ())) a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (a -> Const (First a) a)
-> TurtleData -> Const (First a) TurtleData
Lens' TurtleData a
l)
{-# INLINE getter_ #-}

-- | This is a helper function that extracts the turtle data for a given turtle.

tData_ :: Turtle -> SeqC T.TurtleData
tData_ :: Turtle -> SeqC TurtleData
tData_ = TurtleCommand TurtleData -> SeqC TurtleData
forall a. TurtleCommand a -> SeqC a
seqT (TurtleCommand TurtleData -> SeqC TurtleData)
-> (Turtle -> TurtleCommand TurtleData)
-> Turtle
-> SeqC TurtleData
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> TurtleData
-> Lens' TurtleData TurtleData
-> Turtle
-> TurtleCommand TurtleData
forall a. a -> Lens' TurtleData a -> Turtle -> TurtleCommand a
getter_ TurtleData
T.defaultTurtle forall a. a -> a
Lens' TurtleData TurtleData
id
{-# INLINE tData_ #-}

-- | This is a helper function for our setter commands

-- It takes a lens, the value to apply, and the turtle to modify.

setter_ :: Lens' T.TurtleData b -> b -> Turtle -> TurtleCommand ()
setter_ :: Lens' TurtleData b -> b -> Turtle -> TurtleCommand ()
setter_ Lens' TurtleData b
l b
val Turtle
t = 
  ContT (AlmostVal ()) (TurtleState (AlmostVal ())) ()
-> TurtleCommand ()
forall a. SeqC a -> TurtleCommand a
TurtleCommand (ContT (AlmostVal ()) (TurtleState (AlmostVal ())) ()
 -> TurtleCommand ())
-> ContT (AlmostVal ()) (TurtleState (AlmostVal ())) ()
-> TurtleCommand ()
forall a b. (a -> b) -> a -> b
$ Turtle
-> (TurtleData -> Identity TurtleData)
-> TSC (AlmostVal ())
-> Identity (TSC (AlmostVal ()))
forall (f :: * -> *) b.
Applicative f =>
Turtle -> (TurtleData -> f TurtleData) -> TSC b -> f (TSC b)
turtLens_ Turtle
t ((TurtleData -> Identity TurtleData)
 -> TSC (AlmostVal ()) -> Identity (TSC (AlmostVal ())))
-> ((b -> Identity b) -> TurtleData -> Identity TurtleData)
-> (b -> Identity b)
-> TSC (AlmostVal ())
-> Identity (TSC (AlmostVal ()))
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (b -> Identity b) -> TurtleData -> Identity TurtleData
Lens' TurtleData b
l ((b -> Identity b)
 -> TSC (AlmostVal ()) -> Identity (TSC (AlmostVal ())))
-> b -> ContT (AlmostVal ()) (TurtleState (AlmostVal ())) ()
forall s (m :: * -> *) a b.
MonadState s m =>
ASetter s s a b -> b -> m ()
.= b
val
{-# INLINE setter_ #-}