mirror of
https://github.com/iritmaximus/haskell.git
synced 2026-10-12 19:13:39 +03:00
add Set8
This commit is contained in:
@@ -0,0 +1,474 @@
|
||||
module Set8 where
|
||||
|
||||
import Data.Char (intToDigit)
|
||||
|
||||
import Mooc.Todo
|
||||
|
||||
-- This is the final project for Introduction to Functional
|
||||
-- Programming, part 1. We'll be developing a sort of functional image
|
||||
-- library together. This file is made up of explanations (like this)
|
||||
-- and some prepared code. Some definitions you'll have to fill in
|
||||
-- yourself, just like in the previous exercise sets.
|
||||
|
||||
-- We'll use the JuicyPixels library to generate images. The library
|
||||
-- exposes the Codec.Picture module that has everything we need.
|
||||
import Codec.Picture
|
||||
|
||||
-- Let's start by defining Colors and Pictures.
|
||||
|
||||
-- A Color is just three numbers: the red, green and blue components.
|
||||
-- We use Ints for convenience even though the valid range is only
|
||||
-- 0-255.
|
||||
data Color = Color Int Int Int
|
||||
deriving (Show,Eq)
|
||||
|
||||
getRed :: Color -> Int
|
||||
getRed (Color r _ _) = r
|
||||
getGreen :: Color -> Int
|
||||
getGreen (Color _ g _) = g
|
||||
getBlue :: Color -> Int
|
||||
getBlue (Color _ _ b) = b
|
||||
|
||||
-- Here are some colors
|
||||
|
||||
black :: Color
|
||||
black = Color 0 0 0
|
||||
|
||||
white :: Color
|
||||
white = Color 255 255 255
|
||||
|
||||
pink :: Color
|
||||
pink = Color 255 105 180
|
||||
|
||||
red :: Color
|
||||
red = Color 255 0 0
|
||||
|
||||
yellow :: Color
|
||||
yellow = Color 255 240 0
|
||||
|
||||
-- A coordinate is two Ints, x and y.
|
||||
|
||||
data Coord = Coord Int Int
|
||||
|
||||
-- A Picture is a wrapper for a function of type Coord -> Color.
|
||||
-- The function takes in x and y coordinates and returns a color.
|
||||
|
||||
data Picture = Picture (Coord -> Color)
|
||||
|
||||
-- Here's a picture that's just a white dot at 10,10
|
||||
justADot = Picture f
|
||||
where f (Coord 10 10) = white
|
||||
f _ = black
|
||||
|
||||
-- Here's a picture that's just a solid color
|
||||
solid :: Color -> Picture
|
||||
solid color = Picture (\coord -> color)
|
||||
|
||||
-- Here's a simple picture:
|
||||
examplePicture1 = Picture f
|
||||
where f (Coord x y) | abs (x+y) < 100 = pink
|
||||
| max x y < 200 = white
|
||||
| otherwise = black
|
||||
|
||||
|
||||
-- In order to find out what our example picture looks like, here's a
|
||||
-- function that renders a Picture into a png file.
|
||||
--
|
||||
-- In addition to the Picture it takes a width and a height.
|
||||
--
|
||||
-- The return type is IO (), which you don't need to worry about right
|
||||
-- now. A value of type IO () is something that can be executed by
|
||||
-- Haskell to produce side effects (like the creation of a file in
|
||||
-- this case).
|
||||
|
||||
render :: Picture -> Int -> Int -> String -> IO ()
|
||||
render (Picture f) w h name = writePng name (generateImage (\x y -> colorToPixel (f (Coord x y))) w h)
|
||||
where colorToPixel :: Color -> PixelRGB8
|
||||
colorToPixel (Color r g b) = PixelRGB8 (fromIntegral r) (fromIntegral g) (fromIntegral b)
|
||||
|
||||
-- To see examplePicture1, run this in GHCi:
|
||||
--
|
||||
-- render examplePicture1 400 300 "example1.png"
|
||||
--
|
||||
-- This should produce an example1.png file.
|
||||
--
|
||||
-- Remember: You can get open GHCi with `stack ghci Set8Project.hs`
|
||||
|
||||
-- For testing purposes, let's also define some functions for drawing
|
||||
-- pictures as lists. It's customary to show colours as hexadecimal
|
||||
-- strings. This is what colorToHex does.
|
||||
|
||||
showHex :: Int -> String
|
||||
showHex i = [digit (div i 16), digit (mod i 16)]
|
||||
where digit x | x>=0 && x<16 = intToDigit x
|
||||
| otherwise = 'X'
|
||||
|
||||
colorToHex :: Color -> String
|
||||
colorToHex (Color r g b) = showHex r ++ showHex g ++ showHex b
|
||||
|
||||
getPixel :: Picture -> Int -> Int -> String
|
||||
getPixel (Picture f) x y = colorToHex (f (Coord x y))
|
||||
|
||||
renderList :: Picture -> (Int,Int) -> (Int,Int) -> [[String]]
|
||||
renderList picture (minx,maxx) (miny,maxy) =
|
||||
[[getPixel picture x y | x <- [minx..maxx]] | y <- (reverse [miny..maxy])]
|
||||
|
||||
-- renderListExample evaluates to
|
||||
-- [["000000","000000","000000"],
|
||||
-- ["000000","ffffff","000000"],
|
||||
-- ["000000","000000","000000"]]
|
||||
renderListExample = renderList justADot (9,11) (9,11)
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Ex 1: define a picture dotAndLine that has a white dot at (3,4) and
|
||||
-- a pink line at y=8. Everywhere else, the picture is black.
|
||||
--
|
||||
-- Example:
|
||||
-- renderList dotAndLine (2,4) (3,9) ==>
|
||||
-- [["000000","000000","000000"],
|
||||
-- ["ff69b4","ff69b4","ff69b4"],
|
||||
-- ["000000","000000","000000"],
|
||||
-- ["000000","000000","000000"],
|
||||
-- ["000000","000000","000000"],
|
||||
-- ["000000","ffffff","000000"],
|
||||
-- ["000000","000000","000000"]]
|
||||
|
||||
dotAndLine :: Picture
|
||||
dotAndLine = todo
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Ex 2: blending colors and images.
|
||||
--
|
||||
-- Implement the function blendColor that averages two Colors,
|
||||
-- component by component.
|
||||
--
|
||||
-- Implement the function combine that takes a function and two images
|
||||
-- and makes a new image by applying the function to the corresponding
|
||||
-- pixels of the original images. For example,
|
||||
--
|
||||
-- combine blendColor p1 p2
|
||||
--
|
||||
-- should average two images, pixel by pixel.
|
||||
--
|
||||
-- Examples:
|
||||
-- blendColor (Color 10 100 0) (Color 0 200 40)
|
||||
-- ==> Color 5 150 20
|
||||
-- renderList (combine blendColor (solid red) justADot) (9,11) (9,11)
|
||||
-- ==> [["7f0000","7f0000","7f0000"],
|
||||
-- ["7f0000","ff7f7f","7f0000"],
|
||||
-- ["7f0000","7f0000","7f0000"]]
|
||||
|
||||
blendColor :: Color -> Color -> Color
|
||||
blendColor = todo
|
||||
|
||||
combine :: (Color -> Color -> Color) -> Picture -> Picture -> Picture
|
||||
combine = todo
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
-- Let's define blend, we'll use it later
|
||||
blend :: Picture -> Picture -> Picture
|
||||
blend = combine blendColor
|
||||
|
||||
-- In order to draw some more interesting stuff, let's define the
|
||||
-- notion of a Shape. A Shape is just a function that takes in
|
||||
-- coordinates and returns a boolean indicating whether the
|
||||
-- coordinates belong to the shape.
|
||||
|
||||
data Shape = Shape (Coord -> Bool)
|
||||
|
||||
-- Here's a utility for testing
|
||||
contains :: Shape -> Int -> Int -> Bool
|
||||
contains (Shape f) x y = f (Coord x y)
|
||||
|
||||
-- The simplest shape is a dot. Here's a function that returns a dot
|
||||
-- in a given position.
|
||||
|
||||
dot :: Int -> Int -> Shape
|
||||
dot x y = Shape f
|
||||
where f (Coord cx cy) = (x==cx) && (y==cy)
|
||||
|
||||
-- Here's the definitions of a circle
|
||||
|
||||
circle :: Int -> Int -> Int -> Shape
|
||||
circle r cx cy = Shape f
|
||||
where f (Coord x y) = (x-cx)^2 + (y-cy)^2 < r^2
|
||||
|
||||
-- To be able to draw a Shape we need to convert it to a Picture.
|
||||
-- Here's one way: fill the shape with a given color.
|
||||
|
||||
fill :: Color -> Shape -> Picture
|
||||
fill c (Shape f) = Picture g
|
||||
where g coord | f coord = c
|
||||
| otherwise = black
|
||||
|
||||
-- Here's a picture of a red circle. You can see it by running
|
||||
-- render exampleCircle 400 300 "circle.png"
|
||||
|
||||
exampleCircle :: Picture
|
||||
exampleCircle = fill red (circle 80 100 200)
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Ex 3: implement a rectangle. The value of `rectangle x0 y0 w h`
|
||||
-- should be a rectangle with a corner at (x0, y0), a width of w, and
|
||||
-- a height of h.
|
||||
--
|
||||
-- Example:
|
||||
-- renderList (fill white (rectangle 1 2 2 3)) (0,5) (0,5)
|
||||
-- ==> [["000000","000000","000000","000000","000000","000000"],
|
||||
-- ["000000","ffffff","ffffff","000000","000000","000000"],
|
||||
-- ["000000","ffffff","ffffff","000000","000000","000000"],
|
||||
-- ["000000","ffffff","ffffff","000000","000000","000000"],
|
||||
-- ["000000","000000","000000","000000","000000","000000"],
|
||||
-- ["000000","000000","000000","000000","000000","000000"]]
|
||||
|
||||
|
||||
rectangle :: Int -> Int -> Int -> Int -> Shape
|
||||
rectangle x0 y0 w h = todo
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Ex 4: combining shapes.
|
||||
--
|
||||
-- We defined Shape in addition to Picture because some operations are
|
||||
-- easier to define for Shapes. Implement the union and cut functions.
|
||||
--
|
||||
-- Any point that belongs to one of the shapes should
|
||||
-- belong to the union.
|
||||
--
|
||||
-- Cut should remove all points of the second shape from the first
|
||||
-- shape.
|
||||
|
||||
union :: Shape -> Shape -> Shape
|
||||
union = todo
|
||||
|
||||
cut :: Shape -> Shape -> Shape
|
||||
cut = todo
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
-- Here's a snowman, built using union from circles and rectangles.
|
||||
-- See it by running
|
||||
-- render exampleSnowman 400 300 "snowman.png"
|
||||
|
||||
exampleSnowman :: Picture
|
||||
exampleSnowman = fill white snowman
|
||||
where snowman = union (cut body mouth) hat
|
||||
mouth = rectangle 180 180 40 5
|
||||
body = union (circle 50 200 250) (circle 40 200 170)
|
||||
hat = union (rectangle 170 130 60 5) (rectangle 180 100 40 30)
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Ex 5: even though we can combine Shapes and convert them to Pictures, we
|
||||
-- can't easily add something to a Picture. Let's fix that.
|
||||
--
|
||||
-- Implement the function paintSolid that takes a color and a shape,
|
||||
-- and draws them on top of an existing picture.
|
||||
--
|
||||
-- Example: renderList (paintSolid pink (dot 10 11) justADot) (9,11) (9,11)
|
||||
-- [["000000","ff69b4","000000"],
|
||||
-- ["000000","ffffff","000000"],
|
||||
-- ["000000","000000","000000"]]
|
||||
|
||||
paintSolid :: Color -> Shape -> Picture -> Picture
|
||||
paintSolid color shape base = todo
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
allWhite :: Picture
|
||||
allWhite = solid white
|
||||
|
||||
-- Here's a colorful version of the snowman example. See it by running:
|
||||
-- render exampleColorful 400 300 "colorful.png"
|
||||
|
||||
exampleColorful :: Picture
|
||||
exampleColorful = (paintSolid black hat . paintSolid red legs . paintSolid pink body) allWhite
|
||||
where legs = circle 50 200 250
|
||||
body = circle 40 200 170
|
||||
hat = union (rectangle 170 130 60 5) (rectangle 180 100 40 30)
|
||||
|
||||
-- How about painting with a pattern instead of a solid color? Here
|
||||
-- are the definitions of two patterns (Pictures).
|
||||
|
||||
stipple :: Color -> Color -> Picture
|
||||
stipple a b = Picture f
|
||||
where f (Coord x y) | even x == even y = a
|
||||
| otherwise = b
|
||||
|
||||
stripes :: Color -> Color -> Picture
|
||||
stripes a b = Picture f
|
||||
where f (Coord x y) | even y = a
|
||||
| otherwise = b
|
||||
|
||||
-- You can check them out:
|
||||
-- render (stipple red white) 50 50 "stipple.png"
|
||||
-- render (stripes pink black) 50 50 "stripes.png"
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Ex 6: implement a function paint that works like paintSolid, except
|
||||
-- the first argument is a pattern (as a Picture).
|
||||
--
|
||||
-- Example:
|
||||
-- renderList (paint (stripes red white) (rectangle 0 0 2 4) (solid black)) (0,4) (0,4)
|
||||
-- ==> [["000000","000000","000000","000000","000000"],
|
||||
-- ["ffffff","ffffff","000000","000000","000000"],
|
||||
-- ["ff0000","ff0000","000000","000000","000000"],
|
||||
-- ["ffffff","ffffff","000000","000000","000000"],
|
||||
-- ["ff0000","ff0000","000000","000000","000000"]]
|
||||
|
||||
paint :: Picture -> Shape -> Picture -> Picture
|
||||
paint pat shape base = todo
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
-- Here's a patterned version of the snowman example. See it by running:
|
||||
-- render examplePatterns 400 300 "patterns.png"
|
||||
|
||||
examplePatterns :: Picture
|
||||
examplePatterns = (paint (solid black) hat . paint (stripes red yellow) legs . paint (stipple pink black) body) allWhite
|
||||
where legs = circle 50 200 250
|
||||
body = circle 40 200 170
|
||||
hat = union (rectangle 170 130 60 5) (rectangle 180 100 40 30)
|
||||
|
||||
-- What if we want vertical stripes? What if we want wider stripes?
|
||||
-- Let's implement zooming and flipping images.
|
||||
|
||||
flipCoordXY :: Coord -> Coord
|
||||
flipCoordXY (Coord x y) = (Coord y x)
|
||||
|
||||
-- Flip a picture by switching x and y coordinates
|
||||
flipXY :: Picture -> Picture
|
||||
flipXY (Picture f) = Picture (f . flipCoordXY)
|
||||
|
||||
zoomCoord :: Int -> Coord -> Coord
|
||||
zoomCoord z (Coord x y) = Coord (div x z) (div y z)
|
||||
|
||||
-- Zoom a picture: scale it up by a factor of z
|
||||
zoom :: Int -> Picture -> Picture
|
||||
zoom z (Picture f) = Picture (f . zoomCoord z)
|
||||
|
||||
-- Here are some large vertical stripes. See them by running
|
||||
-- render largeVerticalStripes 400 300 "large-stripes.png"
|
||||
largeVerticalStripes = zoom 5 (flipXY (stripes red yellow))
|
||||
|
||||
-- To support all sorts of image transforms let's use a type class
|
||||
-- Transform. A Transform is something that you can apply to an image.
|
||||
|
||||
class Transform t where
|
||||
apply :: t -> Picture -> Picture
|
||||
|
||||
-- Here's a simple image for testing transformations
|
||||
xy :: Picture
|
||||
xy = Picture f
|
||||
where f (Coord x y) = Color (mod x 256) (mod y 256) 0
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Ex 7: implement Transform instances for the Fill, Zoom and Flip types.
|
||||
--
|
||||
-- The Fill transform should fill the image completely with the given color.
|
||||
--
|
||||
-- The Zoom transform should scale a picture up just like the zoom function above.
|
||||
--
|
||||
-- The FlipX transform should flip the image along the vertical axis,
|
||||
-- i.e. map (10,15) to (10,-15).
|
||||
--
|
||||
-- The FlipY transform should flip the image along the horizontal
|
||||
-- axis, i.e. map (10,15) to (-10,15).
|
||||
--
|
||||
-- The FlipXY transform should switch the x and y coordinates, i.e.
|
||||
-- map (10,15) to (15,10).
|
||||
|
||||
data Fill = Fill Color
|
||||
|
||||
instance Transform Fill where
|
||||
apply = todo
|
||||
|
||||
data Zoom = Zoom Int
|
||||
deriving Show
|
||||
|
||||
instance Transform Zoom where
|
||||
apply = todo
|
||||
|
||||
data Flip = FlipX | FlipY | FlipXY
|
||||
deriving Show
|
||||
|
||||
instance Transform Flip where
|
||||
apply = todo
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Ex 8: the Chain type represents a combination of two transforms.
|
||||
-- Implement a Transform instance for Chain.
|
||||
--
|
||||
-- When (Chain t1 t2) is applied to an image, t2 is first applied to
|
||||
-- the image, and then t1.
|
||||
--
|
||||
-- Hint: you might need a constraint on the instance
|
||||
|
||||
data Chain a b = Chain a b
|
||||
deriving Show
|
||||
|
||||
instance Transform (Chain a b) where
|
||||
apply = todo
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
-- Now we can redefine largeVerticalStripes using the above Transforms.
|
||||
-- See the picture by running
|
||||
-- render largeVerticalStripes2 400 300 "large-stripes2.png"
|
||||
largeVerticalStripes2 :: Picture
|
||||
largeVerticalStripes2 = apply (Chain (Zoom 5) FlipXY) (stripes red yellow)
|
||||
|
||||
-- We can also define a nice checkered pattern by overlaying two stripes.
|
||||
-- See it by running
|
||||
-- render checkered 400 30 "checkered.png"
|
||||
flipBlend :: Picture -> Picture
|
||||
flipBlend picture = blend picture (apply FlipXY picture)
|
||||
|
||||
checkered :: Picture
|
||||
checkered = flipBlend largeVerticalStripes2
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Ex 9: implement a Transform instance for Blur.
|
||||
--
|
||||
-- Produce a blurred version of an image by taking the average colors
|
||||
-- of a pixel and its 4 neighbours.
|
||||
--
|
||||
-- PS. Use rounding down integer division (i.e. the div function) for
|
||||
-- the average.
|
||||
--
|
||||
-- Example: renderList (apply Blur justADot) (8,12) (8,12)
|
||||
-- ==> [["000000","000000","000000","000000","000000"],
|
||||
-- ["000000","000000","333333","000000","000000"],
|
||||
-- ["000000","333333","333333","333333","000000"],
|
||||
-- ["000000","000000","333333","000000","000000"],
|
||||
-- ["000000","000000","000000","000000","000000"]]
|
||||
|
||||
data Blur = Blur
|
||||
deriving Show
|
||||
|
||||
instance Transform Blur where
|
||||
apply = todo
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Ex 10: blur an image multiple times. Implement a Transform instance
|
||||
-- for BlurMany. The transform BlurMany n should perform Blur n times.
|
||||
--
|
||||
-- Example: renderList (apply (BlurMany 2) justADot) (8,12) (8,12)
|
||||
-- ==> [["000000","000000","0a0a0a","000000","000000"],
|
||||
-- ["000000","141414","141414","141414","000000"],
|
||||
-- ["0a0a0a","141414","333333","141414","0a0a0a"],
|
||||
-- ["000000","141414","141414","141414","000000"],
|
||||
-- ["000000","000000","0a0a0a","000000","000000"]]
|
||||
|
||||
data BlurMany = BlurMany Int
|
||||
deriving Show
|
||||
|
||||
instance Transform BlurMany where
|
||||
apply = todo
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
-- Here's a blurred version of our original snowman. See it by running
|
||||
-- render blurredSnowman 400 300 "blurred.png"
|
||||
|
||||
blurredSnowman = apply (BlurMany 2) exampleSnowman
|
||||
|
||||
|
||||
@@ -0,0 +1,249 @@
|
||||
{-# LANGUAGE TemplateHaskell, ScopedTypeVariables #-}
|
||||
|
||||
module Set8Test where
|
||||
|
||||
import Data.List hiding (union)
|
||||
import Test.QuickCheck
|
||||
|
||||
import Mooc.Th
|
||||
import Mooc.Test
|
||||
|
||||
import Set8 hiding (main)
|
||||
|
||||
main = score [(1,"dotAndLine",[ex1_line, ex1_dot, ex1_black, ex1_line_far])
|
||||
,(2,"blend",[ex2_blendColor, ex2_render, ex2_solid, ex2_const])
|
||||
,(3,"rectangle",[ex3])
|
||||
,(4,"union",[ex4_union, ex4_cut])
|
||||
,(5,"paintSolid",[ex5_render, ex5_dot])
|
||||
,(6,"paint",[ex6_render, ex6_dot])
|
||||
,(7,"Transform",[ex7_fill, ex7_zoom_xy, ex7_zoom_dot, ex7_flipx, ex7_flipy, ex7_flipxy])
|
||||
,(8,"Chain",[ex8_inverse, ex8_order, ex8_zoom])
|
||||
,(9,"Blur",[ex9_blur_dot, ex9_blur_solid])
|
||||
,(10,"BlurMany",[ex10_blur_once, ex10_blur_many])]
|
||||
|
||||
--
|
||||
|
||||
checkPicture x y exp (Picture f) =
|
||||
counterexample (" color of point (" ++ show x ++ "," ++ show y ++ ")") $
|
||||
(f (Coord x y)) ?== exp
|
||||
|
||||
checkShape x y exp (Shape f) =
|
||||
counterexample (" contains point (" ++ show x ++ "," ++ show y ++ ")") $
|
||||
f (Coord x y) ?== exp
|
||||
|
||||
instance Arbitrary Color where
|
||||
arbitrary = Color <$> comp <*> comp <*> comp
|
||||
where comp = choose (0,255)
|
||||
|
||||
ex1_line = $(testing' [|renderList dotAndLine (2,4) (8,8)|]) (?==[["ff69b4","ff69b4","ff69b4"]])
|
||||
ex1_dot = $(testing' [|renderList dotAndLine (2,4) (4,4)|]) (?==[["000000","ffffff","000000"]])
|
||||
ex1_black = forAll_ $ \(x,y) ->
|
||||
(x,y) /= (3,4) ==>
|
||||
y /= 8 ==>
|
||||
$(testing' [|getPixel dotAndLine x y|]) $ \val ->
|
||||
counterexample (" with x = "++show x++" and y = "++show y) $
|
||||
val ?== "000000"
|
||||
ex1_line_far = forAll_ $ \x ->
|
||||
$(testing' [|getPixel dotAndLine x 8|]) $ \val ->
|
||||
counterexample (" with x = "++show x) $
|
||||
val ?== "ff69b4"
|
||||
|
||||
ex2_blendColor =
|
||||
forAll_ $ \(Color r g b) ->
|
||||
forAllBlind (choose (0,min r (255-r))) $ \r' ->
|
||||
forAllBlind (choose (0,min g (255-g))) $ \g' ->
|
||||
forAllBlind (choose (0,min b (255-r))) $ \b' ->
|
||||
$(testing [|blendColor (Color (r-r') (g-g') (b-b')) (Color (r+r') (g+g') (b+b'))|]) (?== Color r g b)
|
||||
|
||||
ex2_render = conjoin
|
||||
[$(testing' [|renderList (combine blendColor (solid red) justADot) (9,11) (10,10)|])
|
||||
(?==[["7f0000","ff7f7f","7f0000"]])
|
||||
,$(testing' [|renderList (combine blendColor justADot (solid white)) (9,11) (10,10)|])
|
||||
(?==[["7f7f7f","ffffff","7f7f7f"]])]
|
||||
|
||||
ex2_solid = forAll_ $ \c1 ->
|
||||
forAll_ $ \c2 ->
|
||||
forAll_ $ \(x,y) ->
|
||||
counterexample ("combine blendColor (solid ("++show c1++")) (solid ("++show c2++"))") $
|
||||
checkPicture x y (blendColor c1 c2) (combine blendColor (solid c1) (solid c2))
|
||||
|
||||
ex2_const = forAll_ $ \c1 ->
|
||||
forAll_ $ \c2 ->
|
||||
forAll_ $ \(x,y) ->
|
||||
counterexample ("combine (\\c1 c2 -> c1) (solid ("++show c1++")) (solid ("++show c2++"))") $
|
||||
checkPicture x y c1 (combine (\c1 c2 -> c1) (solid c1) (solid c2))
|
||||
|
||||
ex3 = forAll_ $ \(Positive x0,Positive y0) ->
|
||||
forAllBlind (choose (1,10)) $ \w ->
|
||||
forAllBlind (choose (1,10)) $ \h ->
|
||||
$(testing [|rectangle x0 y0 w h|]) $ \rect ->
|
||||
conjoin [checkShape x y True rect | x <- [x0..x0+w-1], y <- [y0..y0+h-1]]
|
||||
.&&. conjoin [checkShape (x0-1) y False rect | y <- [y0-1..y0+h]] -- left
|
||||
.&&. conjoin [checkShape (x0+w) y False rect | y <- [y0-1..y0+h]] -- right
|
||||
.&&. conjoin [checkShape x (y0-1) False rect | x <- [x0-1..x0+w]] -- top
|
||||
.&&. conjoin [checkShape x (y0+h) False rect | x <- [x0-1..x0+w]] -- bottom
|
||||
.&&. conjoin [checkShape (x0-h) (y0-w) False rect
|
||||
,checkShape x0 (y0+h+w) False rect
|
||||
,checkShape (x0+max h w) (y0+1) False rect]
|
||||
|
||||
ex4_union = forAll_ $ \(Positive x0,Positive y0,Positive x1,Positive y1) ->
|
||||
counterexample ("union (dot "++show x0++" "++show y0++") (dot "++show x1++" "++show y0++")") $
|
||||
let un = union (dot x0 y0) (dot x1 y1)
|
||||
in conjoin [checkShape x0 y0 True un
|
||||
,checkShape x1 y1 True un
|
||||
,x0 /= x1 && y0 /= y1 ==> checkShape x1 y0 False un
|
||||
,x0 /= x1 && y0 /= y1 ==> checkShape x0 y1 False un
|
||||
,forAll_ $ \(x,y) -> not (elem x [x0,x1]) && not (elem y [y0,y1]) ==> checkShape x y False un]
|
||||
|
||||
ex4_cut = forAll_ $ \(Positive x0,Positive y0) ->
|
||||
forAllBlind (choose (2,10)) $ \w ->
|
||||
forAllBlind (choose (2,10)) $ \h ->
|
||||
forAllBlind (choose (x0,x0+w-1)) $ \x ->
|
||||
forAllBlind (choose (y0,y0+h-1)) $ \y ->
|
||||
counterexample ("cut (rectangle "++show x0++" "++show y0++" "++show w++" "++show h++") (dot "++show x++" "++show y++")") $
|
||||
let c = cut (rectangle x0 y0 w h) (dot x y)
|
||||
in conjoin [checkShape x y False c
|
||||
,forAllBlind (choose (x0,x0+w-1) `suchThat` (/=x)) $ \x' ->
|
||||
forAllBlind (choose (y0,y0+h-1) `suchThat` (/=y)) $ \y' ->
|
||||
checkShape x' y' True c]
|
||||
|
||||
ex5_render =
|
||||
$(testing' [|renderList (paintSolid white (dot 5 5) (solid black)) (4,6) (5,5)|])
|
||||
(?==[["000000","ffffff","000000"]])
|
||||
|
||||
ex5_dot = forAll_ $ \(x,y) ->
|
||||
forAll_ $ \bg ->
|
||||
forAll_ $ \fg ->
|
||||
let pict = paintSolid fg (dot x y) (solid bg)
|
||||
in counterexample ("paintSolid ("++show fg++") (dot "++show x++" "++show y++") (solid (" ++ show bg ++"))") $
|
||||
conjoin [checkPicture x y fg pict
|
||||
,forAll_ $ \(x1,y1) -> x1/=x || y1/=y ==> checkPicture x1 y1 bg pict]
|
||||
|
||||
ex6_render =
|
||||
conjoin [$(testing' [|renderList (paint (stripes red white) (rectangle 0 0 2 4) (solid black)) (0,4) (1,1)|])
|
||||
(?==[["ffffff","ffffff","000000","000000","000000"]])
|
||||
,$(testing' [|renderList (paint (stripes red white) (rectangle 0 0 2 4) (solid black)) (0,4) (0,0)|])
|
||||
(?==[["ff0000","ff0000","000000","000000","000000"]])]
|
||||
|
||||
ex6_dot = forAll_ $ \(x,y) ->
|
||||
forAll_ $ \bg ->
|
||||
forAll_ $ \fg ->
|
||||
let pict = paint (solid fg) (dot x y) (solid bg)
|
||||
in counterexample ("paint (solid ("++show fg++")) (dot "++show x++" "++show y++") (solid (" ++ show bg ++"))") $
|
||||
conjoin [checkPicture x y fg pict
|
||||
,forAll_ $ \(x1,y1) -> x1/=x || y1/=y ==> checkPicture x1 y1 bg pict]
|
||||
|
||||
ex7_fill = $(testing' [|apply (Fill red) xy|]) $ \pic ->
|
||||
forAll_ $ \(x,y) ->
|
||||
checkPicture x y red pic
|
||||
|
||||
ex7_zoom_xy = $(testing' [|apply (Zoom 3) xy|]) $ \pic ->
|
||||
forAllBlind (choose (0,32)) $ \x ->
|
||||
forAllBlind (choose (0,32)) $ \y ->
|
||||
forAllBlind (choose (0,2)) $ \dx ->
|
||||
forAllBlind (choose (0,2)) $ \dy ->
|
||||
checkPicture (3*x+dx) (3*y+dy) (Color x y 0) pic
|
||||
|
||||
ex7_zoom_dot = forAll_ $ \(x,y) ->
|
||||
forAllBlind (choose (1,10)) $ \z ->
|
||||
$(testing' [|apply (Zoom z) (fill white (dot x y))|]) $ \pic ->
|
||||
counterexample ("with z=" ++ show z ++ ", x=" ++ show x ++ ", y=" ++ show y) $
|
||||
conjoin [checkPicture x' y' white pic | x' <- [x*z..(x+1)*z-1], y' <- [y*z..(y+1)*z-1]] -- inside
|
||||
.&&. conjoin [checkPicture (x*z-1) y' black pic | y' <- [y*z..(y+1)*z-1]] -- left
|
||||
.&&. conjoin [checkPicture ((x+1)*z) y' black pic | y' <- [y*z..(y+1)*z-1]] -- right
|
||||
.&&. conjoin [checkPicture x' (y*z-1) black pic | x' <- [x*z..(x+1)*z-1]] -- top
|
||||
.&&. conjoin [checkPicture x' ((y+1)*z) black pic | x' <- [x*z..(x+1)*z-1]] -- bottom
|
||||
|
||||
ex7_flipx = $(testing' [|apply FlipX xy|]) $ \pic ->
|
||||
forAllBlind (choose (0,255)) $ \x ->
|
||||
forAllBlind (choose (0,255)) $ \y ->
|
||||
checkPicture x y (Color (if x==0 then x else (256-x)) y 0) pic
|
||||
|
||||
ex7_flipy = $(testing' [|apply FlipY xy|]) $ \pic ->
|
||||
forAllBlind (choose (0,255)) $ \x ->
|
||||
forAllBlind (choose (0,255)) $ \y ->
|
||||
checkPicture x y (Color x (if y==0 then y else (256-y)) 0) pic
|
||||
|
||||
ex7_flipxy = $(testing' [|apply FlipXY xy|]) $ \pic ->
|
||||
forAllBlind (choose (0,255)) $ \x ->
|
||||
forAllBlind (choose (0,255)) $ \y ->
|
||||
checkPicture x y (Color y x 0) pic
|
||||
|
||||
ex8_inverse = $(testing' [|apply (Chain FlipX FlipX) xy|]) $ \pic ->
|
||||
forAllBlind (choose (0,255)) $ \x ->
|
||||
forAllBlind (choose (0,255)) $ \y ->
|
||||
checkPicture x y (Color x y 0) pic
|
||||
|
||||
ex8_order = $(testing' [|apply (Chain (Fill white) (Fill red)) xy|]) $ \pic ->
|
||||
forAll_ $ \(x,y) ->
|
||||
checkPicture x y white pic
|
||||
|
||||
ex8_zoom =
|
||||
forAllBlind (choose (1,4)) $ \z1 ->
|
||||
forAllBlind (choose (1,4)) $ \z2 ->
|
||||
$(testing [|apply (Chain (Zoom z1) (Zoom z2))|]) $ \app ->
|
||||
counterexample "applied to xy" $
|
||||
let pic = app xy
|
||||
z = z1*z2
|
||||
in forAllBlind (choose (0,32)) $ \x ->
|
||||
forAllBlind (choose (0,32)) $ \y ->
|
||||
forAllBlind (choose (0,z-1)) $ \dx ->
|
||||
forAllBlind (choose (0,z-1)) $ \dy ->
|
||||
checkPicture (z*x+dx) (z*y+dy) (Color x y 0) pic
|
||||
|
||||
ex9_blur_dot = forAll_ $ \(x,y) ->
|
||||
forAllBlind (choose (0,50)) $ \c ->
|
||||
let blurred = Color c c c
|
||||
c1 = c*5
|
||||
color = Color c1 c1 c1
|
||||
in $(testing' [|apply Blur (fill color (dot x y))|]) $ \pic ->
|
||||
counterexample ("with color = " ++ show color ++ ", x = " ++ show x ++ ", y = " ++ show y) $
|
||||
conjoin [checkPicture x y blurred pic
|
||||
,checkPicture (x+1) y blurred pic
|
||||
,checkPicture (x-1) y blurred pic
|
||||
,checkPicture x (y+1) blurred pic
|
||||
,checkPicture x (y-1) blurred pic
|
||||
,checkPicture (x-1) (y-1) black pic
|
||||
,checkPicture (x+1) (y+1) black pic
|
||||
,checkPicture (x-1) (y+1) black pic
|
||||
,checkPicture (x+1) (y-1) black pic]
|
||||
|
||||
ex9_blur_solid =
|
||||
forAll_ $ \color ->
|
||||
forAll_ $ \(x,y) ->
|
||||
$(testing' [|apply Blur (solid color)|]) $ \pic ->
|
||||
counterexample ("with color = "++show color) $
|
||||
checkPicture x y color pic
|
||||
|
||||
ex10_blur_once = forAll_ $ \(x,y) ->
|
||||
forAllBlind (choose (0,50)) $ \c ->
|
||||
let blurred = Color c c c
|
||||
c1 = c*5
|
||||
color = Color c1 c1 c1
|
||||
in $(testing' [|apply (BlurMany 1) (fill color (dot x y))|]) $ \pic ->
|
||||
counterexample ("with color = " ++ show color ++ ", x = " ++ show x ++ ", y = " ++ show y) $
|
||||
conjoin [checkPicture x y blurred pic
|
||||
,checkPicture (x+1) y blurred pic
|
||||
,checkPicture (x-1) y blurred pic
|
||||
,checkPicture x (y+1) blurred pic
|
||||
,checkPicture x (y-1) blurred pic
|
||||
,checkPicture (x-1) (y-1) black pic
|
||||
,checkPicture (x+1) (y+1) black pic
|
||||
,checkPicture (x-1) (y+1) black pic
|
||||
,checkPicture (x+1) (y-1) black pic]
|
||||
|
||||
ex10_blur_many = forAll_ $ \(x,y) ->
|
||||
forAllBlind (choose (1,6)) $ \n ->
|
||||
forAll_ $ \color ->
|
||||
let b = BlurMany n
|
||||
b' = BlurMany (n-1)
|
||||
f = apply b
|
||||
g = apply Blur . apply b'
|
||||
img = fill color (dot x y)
|
||||
in counterexample ("Checking that\n apply ("++show b++")\ngives the same result as\n apply Blur . apply ("++show b'++")\non the image") $
|
||||
counterexample (" fill ("++show color++") (dot "++show x++" "++show y++")") $
|
||||
forAllBlind (choose (x-n,x+n)) $ \x' ->
|
||||
forAllBlind (choose (y-n,y+n)) $ \y' ->
|
||||
let (Picture color) = g img
|
||||
expected = color (Coord x' y')
|
||||
in checkPicture x' y' expected (f img)
|
||||
Reference in New Issue
Block a user