module Diagrams.Puzzles.Grid where
import Data.Char (isUpper)
import Diagrams.Prelude
import Data.Puzzles.Grid
import Data.Puzzles.GridShape hiding (size, cells)
import Diagrams.Puzzles.Lib
import Diagrams.Puzzles.Widths
dot :: (Renderable (Path R2) b, Backend b R2) => Diagram b R2
dot = circle 0.05 # fc black # smash
slithergrid :: (Backend b R2, Renderable (Path R2) b) =>
Size -> Diagram b R2
slithergrid s@(x, y) = dots <> phantom' (border s)
where dots = hcatsep . replicate (x + 1) . vcatsep . replicate (y + 1) $ dot
gridlines :: Size -> Path R2
gridlines (w, h) = (decoratePath xaxis . repeat . alignB . vrule . fromIntegral $ h)
<> (decoratePath yaxis . repeat . alignL . hrule . fromIntegral $ w)
where xaxis = fromVertices [ p2 (fromIntegral x, 0) | x <- [1..w1] ]
yaxis = fromVertices [ p2 (0, fromIntegral y) | y <- [1..h1] ]
outframe :: Renderable (Path R2) b => Size -> Diagram b R2
outframe (w, h) = strokePointLoop r # lw fw
where wd = fromIntegral w
hd = fromIntegral h
strokePointLoop = strokeLocTrail . mapLoc (wrapLoop . closeLine)
. fromVertices . map p2
fw = framewidthfactor * gridwidth
e = fw / 2 gridwidth / 2
r = [(e, e), (wd + e, e), (wd + e, hd + e), (e, hd + e)]
grid' :: (Backend b R2, Renderable (Path R2) b) =>
(Diagram b R2 -> Diagram b R2) -> Size -> Diagram b R2
grid' gridstyle s =
outframe s
<> stroke (gridlines s) # lw gridwidth # gridstyle
<> phantom' (border s)
grid :: (Backend b R2, Renderable (Path R2) b) =>
Size -> Diagram b R2
grid = grid' id
bgdashing :: (Semigroup a, HasStyle a) =>
[Double] -> Double -> Colour Double -> a -> a
bgdashing ds offs c x = x # dashing ds offs <> x # lc c
dashes :: [Double]
dashes = [5 / 40, 3 / 40]
dashoffset :: Double
dashoffset = 2.5 / 40
dashedgrid :: (Backend b R2, Renderable (Path R2) b) =>
Size -> Diagram b R2
dashedgrid = grid' $ bgdashing dashes dashoffset white'
where
white' = blend 0.95 white black
atCentres :: (Transformable a, Monoid a, V a ~ R2) =>
(t -> a) -> [(Coord, t)] -> a
atCentres dc = translate (r2 (0.5, 0.5)) . atVertices dc
atCentres' :: (Transformable a, V a ~ R2) => SGrid a -> [a]
atCentres' = translate (r2 (1/2, 1/2)) . atVertices'
atVertices :: (Transformable a, Monoid a, V a ~ R2) =>
(t -> a) -> [(Coord, t)] -> a
atVertices dc = mconcat . map (\ (p, c) -> dc c # translatep p)
atVertices' :: (Transformable a, V a ~ R2) => SGrid a -> [a]
atVertices' g = [ (g ! c) # translatep c | c <- cells g ]
border :: (Backend b R2, Renderable (Path R2) b) => Size -> Diagram b R2
border (w, h) = stroke . translate (r2 (bw, bw)) . alignBL
$ rect (fromIntegral w + 2 * bw) (fromIntegral h + 2 * bw)
where
bw = borderwidth
edge :: Edge -> Path R2
edge (E c d) = rule d # translate (r2i c)
where
rule V = vrule 1.0 # alignB
rule H = hrule 1.0 # alignL
dualEdge :: Edge -> Path R2
dualEdge = translate (r2 (1/2, 1/2)) . edge
edgeStyle :: HasStyle a => a -> a
edgeStyle = lineCap LineCapSquare . lw edgewidth
thinEdgeStyle :: HasStyle a => a -> a
thinEdgeStyle = lineCap LineCapSquare . lw onepix
drawEdges :: Renderable (Path R2) b => [Edge] -> Diagram b R2
drawEdges = edgeStyle . stroke . mconcat . map edge
drawDualEdges :: Renderable (Path R2) b => [Edge] -> Diagram b R2
drawDualEdges = edgeStyle . stroke . mconcat . map dualEdge
drawThinDualEdges :: Renderable (Path R2) b => [Edge] -> Diagram b R2
drawThinDualEdges = thinEdgeStyle . stroke . mconcat . map dualEdge
drawAreaGrid :: (Backend b R2, Renderable (Path R2) b, Eq a) =>
SGrid a -> Diagram b R2
drawAreaGrid = drawEdges . borders <> grid . size
fillBG :: (Backend b R2, Renderable (Path R2) b) => Colour Double -> Diagram b R2
fillBG c = square 1 # fc c
shadeGrid :: (Backend b R2, Renderable (Path R2) b) =>
SGrid (Maybe (Colour Double)) -> Diagram b R2
shadeGrid = mconcat . atCentres' . fmap (maybe mempty fillBG)
drawShadedGrid :: (Backend b R2, Renderable (Path R2) b) =>
SGrid Bool -> Diagram b R2
drawShadedGrid = shadeGrid . fmap f
where
f True = Just gray
f False = Nothing
drawAreaGridGray :: (Backend b R2, Renderable (Path R2) b) =>
SGrid Char -> Diagram b R2
drawAreaGridGray = drawAreaGrid <> shadeGrid . fmap cols
where
cols c | isUpper c = Just (blend 0.1 black white)
| otherwise = Nothing