mirror of
https://github.com/reanimate/reanimate.git
synced 2026-09-18 03:12:40 +00:00
Add two more (in-progress) videos.
Former-commit-id: 77c27c81c6eaaa4410a21d053dc4d32185860719
This commit is contained in:
parent
a15c6a7a98
commit
516a4b3f7c
2 changed files with 323 additions and 0 deletions
102
videos/bakers-algorithm/bakers-algorithm.hs
Executable file
102
videos/bakers-algorithm/bakers-algorithm.hs
Executable file
|
|
@ -0,0 +1,102 @@
|
|||
#!/usr/bin/env stack
|
||||
-- stack --resolver lts-13.14 runghc --package reanimate
|
||||
{-# LANGUAGE OverloadedStrings #-}
|
||||
{-# LANGUAGE RecordWildCards #-}
|
||||
module Main (main) where
|
||||
|
||||
import Control.Lens
|
||||
|
||||
import Graphics.SvgTree
|
||||
import Reanimate.Driver (reanimate)
|
||||
import Reanimate.LaTeX
|
||||
import Reanimate.Monad
|
||||
import Reanimate.Svg
|
||||
import Reanimate.Signal
|
||||
|
||||
{- Script
|
||||
|
||||
Computer memory is a finite resource: If it is not reused, it'll eventually
|
||||
run out.
|
||||
|
||||
|
||||
|
||||
-}
|
||||
|
||||
-- screen width 320
|
||||
-- screen height 180
|
||||
{-
|
||||
[flat (1/3) 0, linear (1/3) 0 1, linear (1/3) 1 0]
|
||||
-}
|
||||
main :: IO ()
|
||||
main = reanimate $ pauseAtEnd 2
|
||||
(mkAnimation 0 $ emit $ mkBackground "black") `sim`
|
||||
drawBox
|
||||
|
||||
drawBox :: Animation
|
||||
drawBox = mkAnimation 5 $ do
|
||||
emit $ withFillColor "white" $
|
||||
translate 0 (-70) $
|
||||
scale 2 $ center $ latex "Baker's Algorithm"
|
||||
s <- getSignal $ signalFromList [(0.7, signalFlat 0), (1, signalLinear)]
|
||||
d <- getSignal $ signalFromList [(0.7, signalFlat 0), (1, signalLinear)]
|
||||
draw <- getSignal $ signalFromList [(0.5, signalLinear), (1, signalFlat 1)]
|
||||
let mlc = MemoryLineChart
|
||||
{ mlcWidth = 230
|
||||
, mlcHeight = 50 + s*50
|
||||
, mlcDivider = d
|
||||
, mlcOuterBox = draw }
|
||||
emit $ translate 0 20 $ renderMemoryLineChart mlc
|
||||
|
||||
highlightBox :: Animation
|
||||
highlightBox = mkAnimation 2 $ do
|
||||
emit $ withFillColor "white" $
|
||||
translate 0 (-70) $
|
||||
scale 2 $ center $ latex "Highlightbox"
|
||||
let boxX = negate mlcWidth / 2
|
||||
boxY = negate mlcHeight / 2
|
||||
mlcWidth = 230
|
||||
mlcHeight = 50
|
||||
s <- getSignal $ signalFromList [(0.0, signalFlat 0), (1, signalBell 2)]
|
||||
emit $
|
||||
withStrokeColor "white" $
|
||||
withStrokeWidth (Num $ 0.5 + s) $
|
||||
withFillOpacity 0 $
|
||||
translate (boxX + mlcWidth/2) (boxY + mlcHeight/2) $
|
||||
mkRect (Num mlcWidth) (Num mlcHeight)
|
||||
|
||||
data MemoryLineChart = MemoryLineChart
|
||||
{ mlcWidth :: Double
|
||||
, mlcHeight :: Double
|
||||
, mlcDivider :: Double -- 0 -> 1
|
||||
, mlcOuterBox :: Double -- 0 -> 1
|
||||
}
|
||||
|
||||
mlcBox :: MemoryLineChart -> (Double, Double, Double, Double)
|
||||
mlcBox MemoryLineChart{..} = (boxX, boxY, mlcWidth, mlcHeight)
|
||||
where
|
||||
boxX = negate mlcWidth / 2
|
||||
boxY = negate mlcHeight / 2
|
||||
|
||||
renderMemoryLineChart :: MemoryLineChart -> Tree
|
||||
renderMemoryLineChart MemoryLineChart{..} = mkGroup
|
||||
[ withStrokeColor "white" $
|
||||
withStrokeWidth (Num 0.5) $
|
||||
withFillOpacity 0 $
|
||||
partialSvg mlcOuterBox $ pathify $
|
||||
translate (boxX + mlcWidth/2) (boxY + mlcHeight/2) $
|
||||
mkRect (Num mlcWidth) (Num mlcHeight)
|
||||
, withStrokeColor "white" $
|
||||
withStrokeWidth (Num 0.5) $
|
||||
mkLine (Num (negate $ mlcWidth/2), Num 0)
|
||||
(Num (negate (mlcWidth/2) + lineWidth), Num 0)
|
||||
, withFillColor "white" $
|
||||
translate (negate (mlcWidth/2) - 10) 0 $ rotate (-90) $
|
||||
center $ latex "Memory"
|
||||
, withFillColor "white" $
|
||||
translate 0 (mlcHeight/2 + 10) $
|
||||
center $ latex "Time $\\rightarrow$"
|
||||
]
|
||||
where
|
||||
boxX = negate mlcWidth / 2
|
||||
boxY = negate mlcHeight / 2
|
||||
lineWidth = mlcDivider * mlcWidth
|
||||
221
videos/sorting-algorithms/sorting-algorithms.hs
Executable file
221
videos/sorting-algorithms/sorting-algorithms.hs
Executable file
|
|
@ -0,0 +1,221 @@
|
|||
#!/usr/bin/env stack
|
||||
-- stack --resolver lts-13.14 runghc --package reanimate
|
||||
{-# LANGUAGE OverloadedStrings #-}
|
||||
{-# LANGUAGE RecordWildCards #-}
|
||||
module Main (main) where
|
||||
|
||||
import Control.Lens ()
|
||||
|
||||
import Graphics.SvgTree (Number(..), Tree)
|
||||
import Reanimate.Driver (reanimate)
|
||||
import Reanimate.LaTeX
|
||||
import Reanimate.Monad
|
||||
import Reanimate.Svg
|
||||
import Reanimate.Signal
|
||||
import Reanimate.ColorMap
|
||||
import Codec.Picture.Types
|
||||
import Numeric
|
||||
import qualified Data.Text as T
|
||||
import qualified Geom2D.CubicBezier as Bezier
|
||||
import Data.Fixed
|
||||
import System.Random.Shuffle
|
||||
import System.Random
|
||||
import Data.List
|
||||
|
||||
fixed :: Tree -> Animation -> Animation
|
||||
fixed svg ani = mkAnimation 0 (emit svg) `sim` ani
|
||||
|
||||
digitWidth = 25
|
||||
digitCount = 10
|
||||
|
||||
main :: IO ()
|
||||
main = reanimate $ fixed bg $ pauseAtEnd 1 $
|
||||
mkAnimation 5 $ do
|
||||
s <- getSignal $ signalLinear
|
||||
emit $ withFillColor "white" $ translate (negate $ digitWidth*digitCount/2) 0 $
|
||||
-- sortingTransition (zip [9,0,1,2,3,4,5,6,8,7] squares) s
|
||||
-- sortingTransition (zip [9,0,1,2,3,4,5,6,8,7] digits) s
|
||||
-- sortingTransition (zip [1,0,2,3,4,5,6,7,8,9] digiSquares) s
|
||||
-- jumpTransition (zip [1,0,2,3,4,5,6,7,8,9] digiSquares) s
|
||||
renderSortElements (mkJumpSorted lst) s
|
||||
where
|
||||
seed = 0xDEADBEEF
|
||||
lst = shuffle' (zip [0..] digiSquares) 10 (mkStdGen seed)
|
||||
bg = mkBackground "black"
|
||||
msg = "0 1 2 3 4 5 6 7 8 9"
|
||||
digits =
|
||||
map (withStrokeColor "black" . withStrokeWidth (Num 0.2)) $
|
||||
map (lowerTransformations . scale 3 . pathify . center . latex . T.pack . show) [0..9]
|
||||
squares = map center [ withFillColorPixel (promotePixel $ viridis (n/9)) $
|
||||
mkRect (Num $ digitWidth+0.2) (Num digitWidth) | n <- [0..9]]
|
||||
|
||||
digiSquares = zipWith (\a b -> mkGroup [a,b]) squares digits
|
||||
|
||||
-- msg = "Eve"
|
||||
glyphs = lowerTransformations $ scale 3 $ pathify $ center $ latexAlign msg
|
||||
fillText = mkAnimation 1 $ do
|
||||
s <- getSignal signalLinear
|
||||
sat <- getSignal $ signalFromTo 0 0.7 signalLinear
|
||||
emit $ withFillColor "white" $ withStrokeColor "white" $ withStrokeWidth (Num $ 0.4 * (1-s)) $
|
||||
withFillOpacity s glyphs
|
||||
-- withSubglyphs [0] (withFillColorPixel $ toRGBString sat 0.0) $
|
||||
-- withSubglyphs [1] (withFillColorPixel $ toRGBString sat 0.1) $
|
||||
-- withSubglyphs [2] (withFillColorPixel $ toRGBString sat 0.2) $
|
||||
-- withSubglyphs [3] (withFillColorPixel $ toRGBString sat 0.3) $
|
||||
-- withSubglyphs [4] (withFillColorPixel $ toRGBString sat 0.4) $
|
||||
-- withSubglyphs [5] (withFillColorPixel $ toRGBString sat 0.5) $
|
||||
-- withSubglyphs [6] (withFillColorPixel $ toRGBString sat 0.6) $
|
||||
-- withSubglyphs [7] (withFillColorPixel $ toRGBString sat 0.7) $
|
||||
-- withSubglyphs [8] (withFillColorPixel $ toRGBString sat 0.8) $
|
||||
-- withSubglyphs [9] (withFillColorPixel $ toRGBString sat 0.9) $
|
||||
-- glyphs
|
||||
drawText = mkAnimation 2 $ do
|
||||
s <- getSignal signalLinear
|
||||
emit $
|
||||
withStrokeColor "white" $ withFillOpacity 0 $ withStrokeWidth (Num 0.4) $
|
||||
partialSvg s glyphs
|
||||
|
||||
data Direction = Up | Down | Sideways
|
||||
type Delay = Double
|
||||
type Position = Int
|
||||
data SortElement = SortElement
|
||||
{ sortElementDirection :: Direction
|
||||
, sortElementStartTime :: Double
|
||||
, sortElementDuration :: Double
|
||||
, sortElementStartPosition :: Position
|
||||
, sortElementEndPosition :: Position
|
||||
, sortElementTree :: Tree }
|
||||
|
||||
|
||||
mkJumpSorted :: [(Int, Tree)] -> [SortElement]
|
||||
mkJumpSorted = fixParameters . worker Up . zip [0..]
|
||||
where
|
||||
worker _ [] = []
|
||||
worker dir ((nth, (target, elt)):rest) =
|
||||
SortElement
|
||||
{ sortElementDirection = dir
|
||||
, sortElementStartTime = 0
|
||||
, sortElementDuration = 1
|
||||
, sortElementStartPosition = nth
|
||||
, sortElementEndPosition = target
|
||||
, sortElementTree = elt
|
||||
} : worker (flip dir) (yoink target rest)
|
||||
flip Up = Down
|
||||
flip Down = Up
|
||||
|
||||
-- 10
|
||||
-- 1/10
|
||||
-- 0 -> 0.1
|
||||
-- 0.05 -> 0.25
|
||||
-- 0.1
|
||||
fixParameters :: [SortElement] -> [SortElement]
|
||||
fixParameters elts = map setDuration $ setStartTime 0 elts
|
||||
where
|
||||
setStartTime nth [] = []
|
||||
setStartTime nth (elt:elts)
|
||||
| moving elt = elt{sortElementStartTime = fromIntegral nth * duration / 2} :
|
||||
setStartTime (nth+1) elts
|
||||
| otherwise = elt{sortElementDirection=Sideways} : setStartTime nth elts
|
||||
setDuration elt =
|
||||
elt{sortElementDuration = duration}
|
||||
duration = 2 / (moved+1)
|
||||
moved = fromIntegral $ length $ filter moving elts
|
||||
moving SortElement{..} =
|
||||
sortElementStartPosition /= sortElementEndPosition
|
||||
|
||||
yoink :: Int -> [(Int,a)] -> [(Int, a)]
|
||||
yoink n lst =
|
||||
[ (nth, elt) | (nth, elt) <- lst, nth == n ] ++
|
||||
[ (nth, elt) | (nth, elt) <- lst, nth /= n ]
|
||||
|
||||
mkSorted :: [(Int, Tree)] -> [SortElement]
|
||||
mkSorted lst =
|
||||
[ SortElement
|
||||
{ sortElementDirection = if even nth then Up else Down
|
||||
, sortElementStartTime = fromIntegral nth * recip (len*2)
|
||||
, sortElementDuration = recip len
|
||||
, sortElementStartPosition = nth
|
||||
, sortElementEndPosition = target
|
||||
, sortElementTree = elt
|
||||
}
|
||||
| (nth, (target, elt)) <- zip [0..] lst
|
||||
]
|
||||
where
|
||||
len = fromIntegral (length lst)
|
||||
|
||||
renderSortElement :: SortElement -> Double -> Tree
|
||||
renderSortElement SortElement{..} t
|
||||
| t < sortElementStartTime =
|
||||
translate (fromIntegral sortElementStartPosition * digitWidth) 0 sortElementTree
|
||||
| t > sortElementStartTime + sortElementDuration =
|
||||
translate (fromIntegral sortElementEndPosition * digitWidth) 0 sortElementTree
|
||||
| otherwise =
|
||||
let pos = signalCurve 2 $ (t - sortElementStartTime) / sortElementDuration
|
||||
from = sortElementStartPosition
|
||||
to = sortElementEndPosition
|
||||
linear = fromIntegral from + (fromIntegral (to-from))*pos
|
||||
y = case sortElementDirection of
|
||||
Down -> (sin (pos*pi) * digitWidth)
|
||||
Up -> negate (sin (pos*pi) * digitWidth)
|
||||
Sideways -> 0 in
|
||||
translate (linear * digitWidth) y sortElementTree
|
||||
|
||||
renderSortElements :: [SortElement] -> Double -> Tree
|
||||
renderSortElements elts t =
|
||||
mkGroup $
|
||||
[ renderSortElement elt t | elt <- still ] ++
|
||||
[ renderSortElement elt t | elt <- notStill ]
|
||||
where
|
||||
(notStill, still) = partition isMoving elts
|
||||
isMoving SortElement{..} =
|
||||
t > sortElementStartTime && t < sortElementStartTime + sortElementDuration
|
||||
&& sortElementStartPosition /= sortElementEndPosition
|
||||
|
||||
-- 0 -> 0.5 Move first wrong elt up
|
||||
-- 0.5 1 -> Move first wrong elt down
|
||||
-- Move second wrong elt up
|
||||
-- 1 1.5 -> Move second wrong elt down
|
||||
jumpTransition :: [(Int, Tree)] -> Double -> Tree
|
||||
jumpTransition elts s = mkGroup
|
||||
[ case () of
|
||||
() | n < selfBegin ->
|
||||
translate (fromIntegral nth * digitWidth) 0 elt
|
||||
| n > selfEnd ->
|
||||
translate (fromIntegral target * digitWidth) 0 elt
|
||||
| otherwise ->
|
||||
translate (pos * digitWidth) (sin (pos*pi) * digitWidth) elt
|
||||
| (nth, (target, elt)) <- zip [0..] elts
|
||||
, let selfBegin = fromIntegral nth * 0.5
|
||||
selfEnd = fromIntegral nth * 0.5 + 1
|
||||
pos = n - selfBegin
|
||||
]
|
||||
where
|
||||
linear from to = fromIntegral from + (fromIntegral (to-from))*frac
|
||||
n = s * fromIntegral (length elts)
|
||||
frac = n `mod'` 1
|
||||
fracNext = (n+0.5) `mod'` 1
|
||||
|
||||
sortingTransition :: [(Int,Tree)] -> Double -> Tree
|
||||
sortingTransition elts s = mkGroup
|
||||
[ case () of
|
||||
()
|
||||
| nth == target ->
|
||||
translate (fromIntegral nth*digitWidth) 0 elt
|
||||
-- | nth == target || canMoveDirectly nth target ->
|
||||
-- translate (linear nth target*digitWidth) 0 elt
|
||||
| nth < target ->
|
||||
translate (linear nth target*digitWidth) (sin (s*pi) * digitWidth) elt
|
||||
| otherwise ->
|
||||
translate (linear nth target*digitWidth) (negate $ sin (s*pi) * digitWidth) elt
|
||||
| (nth, (target, elt)) <- zip [0..] elts
|
||||
-- , canMoveDirectly nth target
|
||||
]
|
||||
where
|
||||
linear from to = fromIntegral from + (fromIntegral (to-from))*s
|
||||
canMoveDirectly from to
|
||||
| from == to = False
|
||||
| abs (from-to) == 1 = True
|
||||
| otherwise =
|
||||
let next = from + signum (to-from)
|
||||
(target,_) = elts !! next
|
||||
in signum (next-target) == signum (from-to) && canMoveDirectly next to
|
||||
Loading…
Reference in a new issue