A favorite puzzle/paradox of Lewis Carroll based on Fibonacci numbers. The two figures are “obviously” composed of the same pieces, yet they have different areas!
import Diagrams.Backend.SVG.CmdLine
{-# LANGUAGE NoMonomorphismRestriction #-}
import Diagrams.Prelude hiding (tri)
import Data.Colour.SRGB (sRGB24read)
The standard infinite list of Fibonacci numbers.
fibs :: [Int]
= 0 : 1 : zipWith (+) fibs (tail fibs) fibs
Create a grid by gluing together a bunch of squares.
grid :: Int -> Int -> Diagram B
= frame <> lattice
grid x y where s = unitSquare # lw thin
= rect (fromIntegral x) (fromIntegral y)
frame # lw thick
= centerXY . vcat . map hcat . replicate y . replicate x $ s lattice
The trapezoid and triangle shapes, with sides lengths based on two Fibonacci numbers.
tri :: Double -> Double -> Diagram B
trap,= lw none . strokeLoop . closeLine
trap s1 s2 . fromOffsets . map r2 $ [(0,-s2), (s2,0), (0,s1)]
= lw none . strokeLoop . closeLine
tri s1 s2 . fromOffsets . map r2 $ [(s1,0), (0,s1+s2)]
Draw the paradox diagram based on the nth Fibonacci number.
paradox :: Int -> Bool -> Diagram B
= (sq # rotateBy (1/4)
paradox n drawDiags ||| strutX (s2 / 2)
||| rect # rotateBy (1/4)) # centerXY
where f1 = fibs !! n
= fibs !! (n+1)
f2 = fromIntegral f1
s1 = fromIntegral f2
s2
= trap s1 s2 # fc (sRGB24read "#BEC3C7")
trap1 = trap s1 s2 # fc (sRGB24read "#1ABC9C")
trap2 # rotateBy (1/2)
= tri s1 s2 # fc (sRGB24read "#FF6666")
tri1 = tri s1 s2 # fc (sRGB24read "#37485D") tri2
The four shapes assembled into a square.
= (if drawDiags then sqDiags else mempty)
sq <> grid (f1+f2) (f1+f2)
<> sqShapes
= (fromVertices [p2 (0,s2), p2 (s2,s1)] <>
sqDiags 0), p2 (s2,s1+s2)] <>
fromVertices [p2 (s2,0), p2 (s1+s2,s1+s2)])
fromVertices [p2 (s2,# strokeP
# lw thick
# centerXY
= (traps # centerY ||| tris # centerY)
sqShapes # centerXY
= trap2 # alignL
traps # translateY (s1 - s2)
<> trap1
= tri1 # alignBL
tris <> tri2 # rotateBy (1/2)
# alignBL
The four shapes assembled into a rectangle.
= (if drawDiags then rDiags else mempty)
rect <> grid (2*f2 + f1) f2
<> rShapes
= (bot # alignTL <> top # alignTL) # centerXY
rShapes = trap1 # alignB ||| rotateBy (-1/4) tri1 # alignB
bot = rotateBy (1/4) tri2 # alignT ||| trap2 # alignT
top
= (fromVertices [p2 (0,s2), p2 (2*s2+s1, 0)] <>
rDiags 0), p2 (s2,s1)] <>
fromVertices [p2 (s2,+s2,s2-s1), p2 (s1+s2,s2)]
fromVertices [p2 (s1
)# strokeP
# lw thick
# lineCap LineCapRound
# centerXY
Draw the order-4 diagram with thick lines in the middle. Passing the
argument False
causes the thick lines to be omitted, revealing the
skinny gap in the rectangular assembly. Lower-order diagrams make the
gap more obvious; higher-order diagrams make it increasingly less
obvious (but make the grid smaller).
= paradox 4 True # frame 0.5 example
= mainWith (example :: Diagram B) main