packages feed

puzzle-draw 0.1.0.3 → 0.1.0.4

raw patch · 22 files changed

+1272/−294 lines, 22 filesdep +diagrams-cairodep +filepathdep +mtldep ~SVGFontsdep ~aesondep ~basenew-component:exe:drawpuzzlePVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependencies added: diagrams-cairo, filepath, mtl, optparse-applicative

Dependency ranges changed: SVGFonts, aeson, base, blaze-svg, bytestring, containers, deepseq, diagrams-lib, diagrams-svg, hashable, parsec, tasty, tasty-hunit, text, unordered-containers, yaml

API changes (from Hackage documentation)

- Data.Puzzles.Elements: JapBlack :: JapVal
- Data.Puzzles.Elements: JapInt :: Int -> JapVal
- Data.Puzzles.Elements: None :: KropkiDot
- Data.Puzzles.Elements: White :: KropkiDot
- Data.Puzzles.Elements: data JapVal
- Data.Puzzles.Elements: instance Show JapVal
- Data.Puzzles.PuzzleTypes: CountNumbers :: PuzzleType
- Diagrams.Puzzles.Grid: bgdashing :: (Semigroup a, HasStyle a) => [Double] -> Double -> Colour Double -> a -> a
- Diagrams.Puzzles.PuzzleGrids: drawFillo :: (Backend b R2, Renderable (Path R2) b) => SGrid (Clue Int) -> Diagram b R2
- Diagrams.Puzzles.PuzzleTypes: countnumbers :: (Backend b R2, Renderable (Path R2) b) => RenderPuzzle b AreaGrid IntGrid
- Text.Puzzles.PuzzleTypes: countnumbers :: ParsePuzzle AreaGrid IntGrid
- Text.Puzzles.Util: instance FromChar JapVal
+ Data.Puzzles.Elements: Crossing :: Crossing
+ Data.Puzzles.Elements: KBlack :: KropkiDot
+ Data.Puzzles.Elements: KNone :: KropkiDot
+ Data.Puzzles.Elements: KWhite :: KropkiDot
+ Data.Puzzles.Elements: data Black
+ Data.Puzzles.Elements: data Crossing
+ Data.Puzzles.Elements: instance Eq MasyuPearl
+ Data.Puzzles.Elements: instance Show MasyuPearl
+ Data.Puzzles.Elements: type BahnhofClue = Either Int Crossing
+ Data.Puzzles.Grid: OClue :: (Int, Int) -> (Int, Int) -> a -> OutsideClue a
+ Data.Puzzles.Grid: data OutsideClue a
+ Data.Puzzles.Grid: dualEdgesP :: (a -> a -> Bool) -> Grid Square a -> [Edge]
+ Data.Puzzles.Grid: edgesGen :: (a -> a -> Bool) -> (a -> Bool) -> Grid Square a -> [Edge]
+ Data.Puzzles.Grid: edgesP :: (a -> a -> Bool) -> Grid Square a -> [Edge]
+ Data.Puzzles.Grid: instance (Eq s, Eq (Cell s), Eq a) => Eq (Grid s a)
+ Data.Puzzles.Grid: instance Functor OutsideClue
+ Data.Puzzles.Grid: ocBase :: OutsideClue a -> (Int, Int)
+ Data.Puzzles.Grid: ocDir :: OutsideClue a -> (Int, Int)
+ Data.Puzzles.Grid: ocValue :: OutsideClue a -> a
+ Data.Puzzles.Grid: outsideClueList :: OutsideClues a -> [OutsideClue a]
+ Data.Puzzles.GridShape: instance Eq Square
+ Data.Puzzles.PuzzleTypes: Bahnhof :: PuzzleType
+ Data.Puzzles.PuzzleTypes: Cave :: PuzzleType
+ Data.Puzzles.PuzzleTypes: MeanderingNumbers :: PuzzleType
+ Data.Puzzles.PuzzleTypes: typeNames :: [(PuzzleType, String)]
+ Diagrams.Puzzles.CmdLine: RenderOpts :: FilePath -> Double -> RenderOpts
+ Diagrams.Puzzles.CmdLine: _file :: RenderOpts -> FilePath
+ Diagrams.Puzzles.CmdLine: _w :: RenderOpts -> Double
+ Diagrams.Puzzles.CmdLine: checkFormat :: String -> IO ()
+ Diagrams.Puzzles.CmdLine: checkType :: Maybe String -> IO PuzzleType
+ Diagrams.Puzzles.CmdLine: data RenderOpts
+ Diagrams.Puzzles.CmdLine: exitErr :: String -> IO a
+ Diagrams.Puzzles.CmdLine: formats :: [String]
+ Diagrams.Puzzles.CmdLine: readPuzzle :: FilePath -> IO (Either ParseException TypedPuzzle)
+ Diagrams.Puzzles.CmdLine: renderToFile :: RenderOpts -> Diagram B R2 -> IO ()
+ Diagrams.Puzzles.CmdLine: type B = SVG
+ Diagrams.Puzzles.Elements: drawBahnhofClue :: Backend' b => BahnhofClue -> Diagram b R2
+ Diagrams.Puzzles.Elements: drawCrossing :: Backend' b => Crossing -> Diagram b R2
+ Diagrams.Puzzles.Grid: bgdashingG :: (Semigroup a, HasStyle a, V a ~ R2) => [Double] -> Double -> Colour Double -> a -> a
+ Diagrams.Puzzles.Grid: distrib :: (Transformable c, Monoid c, V c ~ R2) => R2 -> (Int, Int) -> Double -> [c] -> c
+ Diagrams.Puzzles.Grid: gridDashing :: (Semigroup a, HasStyle a, V a ~ R2) => a -> a
+ Diagrams.Puzzles.Grid: irregAreaGridX :: Backend' b => SGrid Char -> Diagram b R2
+ Diagrams.Puzzles.Grid: outframe' :: Backend' b => Double -> Size -> Diagram b R2
+ Diagrams.Puzzles.Grid: outsideCells :: (Transformable c, Monoid c, V c ~ R2) => Double -> [OutsideClue [c]] -> c
+ Diagrams.Puzzles.Grid: outsideGen :: (Transformable c, Monoid c, V c ~ R2) => (OutsideClue [c] -> R2) -> Double -> [OutsideClue [c]] -> c
+ Diagrams.Puzzles.Grid: outsideVertices :: (Transformable c, Monoid c, V c ~ R2) => Double -> [OutsideClue [c]] -> c
+ Diagrams.Puzzles.Lib: type Backend' b = (Backend b R2, Renderable (Path R2) b)
+ Diagrams.Puzzles.PuzzleTypes: bahnhof :: Backend' b => RenderPuzzle b (SGrid (Maybe BahnhofClue)) [Edge]
+ Diagrams.Puzzles.PuzzleTypes: cave :: (Backend b R2, Renderable (Path R2) b) => RenderPuzzle b (SGrid (Clue Int)) ShadedGrid
+ Diagrams.Puzzles.PuzzleTypes: meanderingnumbers :: Backend' b => RenderPuzzle b AreaGrid IntGrid
+ Text.Puzzles.PuzzleTypes: bahnhof :: ParsePuzzle (SGrid (Maybe BahnhofClue)) [Edge]
+ Text.Puzzles.PuzzleTypes: cave :: ParsePuzzle (SGrid (Clue Int)) ShadedGrid
+ Text.Puzzles.PuzzleTypes: meanderingnumbers :: ParsePuzzle AreaGrid IntGrid
+ Text.Puzzles.Util: Either' :: Either a b -> Either' a b
+ Text.Puzzles.Util: IntString :: String -> IntString
+ Text.Puzzles.Util: failChar :: Char -> String -> Parser a
+ Text.Puzzles.Util: field :: Path -> Value -> Parser Value
+ Text.Puzzles.Util: instance (FromChar a, FromChar b) => FromChar (Either' a b)
+ Text.Puzzles.Util: instance (FromJSON a, FromJSON b) => FromJSON (Either' a b)
+ Text.Puzzles.Util: instance FromChar Black
+ Text.Puzzles.Util: instance FromChar Crossing
+ Text.Puzzles.Util: instance FromJSON Blank
+ Text.Puzzles.Util: instance FromJSON Blank'
+ Text.Puzzles.Util: instance FromJSON IntString
+ Text.Puzzles.Util: newtype Either' a b
+ Text.Puzzles.Util: newtype IntString
+ Text.Puzzles.Util: parseCharJSON :: FromChar a => Value -> Parser a
+ Text.Puzzles.Util: parseCharMap :: FromJSON a => Value -> Parser (Map Char a)
+ Text.Puzzles.Util: parseExtGrid :: (FromChar a, FromJSON a) => Value -> Parser (SGrid a)
+ Text.Puzzles.Util: parseFrom :: Path -> (Value -> Parser b) -> (Value -> Parser b)
+ Text.Puzzles.Util: parseGridWith :: (Char -> Parser a) -> Value -> Parser (SGrid a)
+ Text.Puzzles.Util: parseOutside :: FromJSON a => Value -> Parser (OutsideClues a)
+ Text.Puzzles.Util: parseWithReplacement :: FromChar a => (Char -> Maybe a) -> Char -> Parser a
+ Text.Puzzles.Util: type Path = [String]
+ Text.Puzzles.Util: unEither' :: Either' a b -> Either a b
+ Text.Puzzles.Util: unIntString :: IntString -> String
- Data.Puzzles.Compose: drawExample' :: (Backend b R2, Renderable (Path R2) b) => PuzzleHandler b ((Value, Maybe Value) -> Parser (Diagram b R2))
+ Data.Puzzles.Compose: drawExample' :: Backend' b => PuzzleHandler b ((Value, Maybe Value) -> Parser (Diagram b R2))
- Data.Puzzles.Compose: handle :: (Backend b R2, Renderable (Path R2) b) => PuzzleHandler b a -> PuzzleType -> a
+ Data.Puzzles.Compose: handle :: Backend' b => PuzzleHandler b a -> PuzzleType -> a
- Data.Puzzles.Elements: Black :: KropkiDot
+ Data.Puzzles.Elements: Black :: Black
- Data.Puzzles.Grid: filterG :: (a -> Bool) -> (Grid s a) -> (Grid s a)
+ Data.Puzzles.Grid: filterG :: (a -> Bool) -> Grid s a -> Grid s a
- Data.Puzzles.GridShape: orientedEdge :: (Cell Square) -> (Cell Square) -> (Edge' (Vertex Square))
+ Data.Puzzles.GridShape: orientedEdge :: Cell Square -> Cell Square -> Edge' (Vertex Square)
- Data.Puzzles.GridShape: squareNeighbours :: [(Int, Int)] -> Square -> (Cell Square) -> [Cell Square]
+ Data.Puzzles.GridShape: squareNeighbours :: [(Int, Int)] -> Square -> Cell Square -> [Cell Square]
- Diagrams.Puzzles.Draw: draw :: (Backend b R2, Renderable (Path R2) b) => PuzzleSol b -> OutputChoice -> Maybe (Diagram b R2)
+ Diagrams.Puzzles.Draw: draw :: Backend' b => PuzzleSol b -> OutputChoice -> Maybe (Diagram b R2)
- Diagrams.Puzzles.Elements: drawChar :: (Renderable (Path R2) b, Backend b R2) => Char -> Diagram b R2
+ Diagrams.Puzzles.Elements: drawChar :: Backend' b => Char -> Diagram b R2
- Diagrams.Puzzles.Elements: drawCompassClue :: (Renderable (Path R2) b, Backend b R2) => CompassC -> Diagram b R2
+ Diagrams.Puzzles.Elements: drawCompassClue :: Backend' b => CompassC -> Diagram b R2
- Diagrams.Puzzles.Elements: drawCross :: Renderable (Path R2) b => Diagram b R2
+ Diagrams.Puzzles.Elements: drawCross :: Backend' b => Diagram b R2
- Diagrams.Puzzles.Elements: drawCurve :: Renderable (Path R2) b => [Edge] -> Diagram b R2
+ Diagrams.Puzzles.Elements: drawCurve :: Backend' b => [Edge] -> Diagram b R2
- Diagrams.Puzzles.Elements: drawInt :: (Renderable (Path R2) b, Backend b R2) => Int -> Diagram b R2
+ Diagrams.Puzzles.Elements: drawInt :: Backend' b => Int -> Diagram b R2
- Diagrams.Puzzles.Elements: drawMarkedWord :: Renderable (Path R2) b => MarkedWord -> QDiagram b R2 Any
+ Diagrams.Puzzles.Elements: drawMarkedWord :: Backend' b => MarkedWord -> QDiagram b R2 Any
- Diagrams.Puzzles.Elements: drawMarkedWords :: Renderable (Path R2) b => [MarkedWord] -> QDiagram b R2 Any
+ Diagrams.Puzzles.Elements: drawMarkedWords :: Backend' b => [MarkedWord] -> QDiagram b R2 Any
- Diagrams.Puzzles.Elements: drawPrimeDiag :: (Backend b R2, Renderable (Path R2) b) => PrimeDiag -> Diagram b R2
+ Diagrams.Puzzles.Elements: drawPrimeDiag :: Backend' b => PrimeDiag -> Diagram b R2
- Diagrams.Puzzles.Elements: drawShade :: Renderable (Path R2) b => Shade -> Diagram b R2
+ Diagrams.Puzzles.Elements: drawShade :: Backend' b => Shade -> Diagram b R2
- Diagrams.Puzzles.Elements: drawSlalomClue :: (Show a, Renderable (Path R2) b, Backend b R2) => a -> Diagram b R2
+ Diagrams.Puzzles.Elements: drawSlalomClue :: (Show a, Backend' b) => a -> Diagram b R2
- Diagrams.Puzzles.Elements: drawTapaClue :: (Backend b R2, Renderable (Path R2) b) => TapaClue -> Diagram b R2
+ Diagrams.Puzzles.Elements: drawTapaClue :: Backend' b => TapaClue -> Diagram b R2
- Diagrams.Puzzles.Elements: drawText :: (Backend b R2, Renderable (Path R2) b) => String -> QDiagram b R2 Any
+ Diagrams.Puzzles.Elements: drawText :: Backend' b => String -> QDiagram b R2 Any
- Diagrams.Puzzles.Elements: drawThermos :: Renderable (Path R2) b => [Thermometer] -> QDiagram b R2 Any
+ Diagrams.Puzzles.Elements: drawThermos :: Backend' b => [Thermometer] -> QDiagram b R2 Any
- Diagrams.Puzzles.Elements: drawTight :: (Renderable (Path R2) b, Backend b R2) => (a -> Diagram b R2) -> Tightfit a -> Diagram b R2
+ Diagrams.Puzzles.Elements: drawTight :: Backend' b => (a -> Diagram b R2) -> Tightfit a -> Diagram b R2
- Diagrams.Puzzles.Elements: drawWords :: (Renderable (Path R2) b, Backend b R2) => [String] -> Diagram b R2
+ Diagrams.Puzzles.Elements: drawWords :: Backend' b => [String] -> Diagram b R2
- Diagrams.Puzzles.Elements: pearl :: (Renderable (Path R2) b, Backend b R2) => MasyuPearl -> Diagram b R2
+ Diagrams.Puzzles.Elements: pearl :: Backend' b => MasyuPearl -> Diagram b R2
- Diagrams.Puzzles.Elements: smallPearl :: (Renderable (Path R2) b, Backend b R2) => MasyuPearl -> Diagram b R2
+ Diagrams.Puzzles.Elements: smallPearl :: Backend' b => MasyuPearl -> Diagram b R2
- Diagrams.Puzzles.Elements: stackWords :: (Backend b R2, Renderable (Path R2) b) => [String] -> QDiagram b R2 Any
+ Diagrams.Puzzles.Elements: stackWords :: Backend' b => [String] -> QDiagram b R2 Any
- Diagrams.Puzzles.Elements: thermo :: Renderable (Path R2) b => [P2] -> QDiagram b R2 Any
+ Diagrams.Puzzles.Elements: thermo :: Backend' b => [P2] -> QDiagram b R2 Any
- Diagrams.Puzzles.Grid: dashedgrid :: (Backend b R2, Renderable (Path R2) b) => Size -> Diagram b R2
+ Diagrams.Puzzles.Grid: dashedgrid :: Backend' b => Size -> Diagram b R2
- Diagrams.Puzzles.Grid: dot :: (Renderable (Path R2) b, Backend b R2) => Diagram b R2
+ Diagrams.Puzzles.Grid: dot :: Backend' b => Diagram b R2
- Diagrams.Puzzles.Grid: drawAreaGrid :: (Backend b R2, Renderable (Path R2) b, Eq a) => SGrid a -> Diagram b R2
+ Diagrams.Puzzles.Grid: drawAreaGrid :: (Backend' b, Eq a) => SGrid a -> Diagram b R2
- Diagrams.Puzzles.Grid: drawAreaGridGray :: (Backend b R2, Renderable (Path R2) b) => SGrid Char -> Diagram b R2
+ Diagrams.Puzzles.Grid: drawAreaGridGray :: Backend' b => SGrid Char -> Diagram b R2
- Diagrams.Puzzles.Grid: drawDualEdges :: Renderable (Path R2) b => [Edge] -> Diagram b R2
+ Diagrams.Puzzles.Grid: drawDualEdges :: Backend' b => [Edge] -> Diagram b R2
- Diagrams.Puzzles.Grid: drawEdges :: Renderable (Path R2) b => [Edge] -> Diagram b R2
+ Diagrams.Puzzles.Grid: drawEdges :: Backend' b => [Edge] -> Diagram b R2
- Diagrams.Puzzles.Grid: drawShadedGrid :: (Backend b R2, Renderable (Path R2) b) => SGrid Bool -> Diagram b R2
+ Diagrams.Puzzles.Grid: drawShadedGrid :: Backend' b => SGrid Bool -> Diagram b R2
- Diagrams.Puzzles.Grid: drawThinDualEdges :: Renderable (Path R2) b => [Edge] -> Diagram b R2
+ Diagrams.Puzzles.Grid: drawThinDualEdges :: Backend' b => [Edge] -> Diagram b R2
- Diagrams.Puzzles.Grid: edgeStyle :: HasStyle a => a -> a
+ Diagrams.Puzzles.Grid: edgeStyle :: (HasStyle a, V a ~ R2) => a -> a
- Diagrams.Puzzles.Grid: fillBG :: (Backend b R2, Renderable (Path R2) b) => Colour Double -> Diagram b R2
+ Diagrams.Puzzles.Grid: fillBG :: Backend' b => Colour Double -> Diagram b R2
- Diagrams.Puzzles.Grid: grid :: (Backend b R2, Renderable (Path R2) b) => Size -> Diagram b R2
+ Diagrams.Puzzles.Grid: grid :: Backend' b => Size -> Diagram b R2
- Diagrams.Puzzles.Grid: grid' :: (Backend b R2, Renderable (Path R2) b) => (Diagram b R2 -> Diagram b R2) -> Size -> Diagram b R2
+ Diagrams.Puzzles.Grid: grid' :: Backend' b => (Diagram b R2 -> Diagram b R2) -> Size -> Diagram b R2
- Diagrams.Puzzles.Grid: irregularGrid :: (Backend b R2, Renderable (Path R2) b) => SGrid a -> Diagram b R2
+ Diagrams.Puzzles.Grid: irregularGrid :: Backend' b => SGrid a -> Diagram b R2
- Diagrams.Puzzles.Grid: outframe :: Renderable (Path R2) b => Size -> Diagram b R2
+ Diagrams.Puzzles.Grid: outframe :: Backend' b => Size -> Diagram b R2
- Diagrams.Puzzles.Grid: plaingrid :: (Backend b R2, Renderable (Path R2) b) => Size -> Diagram b R2
+ Diagrams.Puzzles.Grid: plaingrid :: Backend' b => Size -> Diagram b R2
- Diagrams.Puzzles.Grid: shadeGrid :: (Backend b R2, Renderable (Path R2) b) => SGrid (Maybe (Colour Double)) -> Diagram b R2
+ Diagrams.Puzzles.Grid: shadeGrid :: Backend' b => SGrid (Maybe (Colour Double)) -> Diagram b R2
- Diagrams.Puzzles.Grid: slithergrid :: (Backend b R2, Renderable (Path R2) b) => Size -> Diagram b R2
+ Diagrams.Puzzles.Grid: slithergrid :: Backend' b => Size -> Diagram b R2
- Diagrams.Puzzles.Grid: thinEdgeStyle :: HasStyle a => a -> a
+ Diagrams.Puzzles.Grid: thinEdgeStyle :: (HasStyle a, V a ~ R2) => a -> a
- Diagrams.Puzzles.Lib: besidesL :: (Semigroup m, Backend b R2, Monoid m, Renderable (Path R2) b) => QDiagram b R2 m -> QDiagram b R2 m -> QDiagram b R2 m
+ Diagrams.Puzzles.Lib: besidesL :: (Backend' b, Semigroup m, Monoid m) => QDiagram b R2 m -> QDiagram b R2 m -> QDiagram b R2 m
- Diagrams.Puzzles.Lib: besidesR :: (Semigroup m, Backend b R2, Monoid m, Renderable (Path R2) b) => QDiagram b R2 m -> QDiagram b R2 m -> QDiagram b R2 m
+ Diagrams.Puzzles.Lib: besidesR :: (Backend' b, Semigroup m, Monoid m) => QDiagram b R2 m -> QDiagram b R2 m -> QDiagram b R2 m
- Diagrams.Puzzles.Lib: hline :: Renderable (Path R2) b => Double -> Diagram b R2
+ Diagrams.Puzzles.Lib: hline :: Backend' b => Double -> Diagram b R2
- Diagrams.Puzzles.Lib: phantom' :: Backend b R2 => D R2 -> Diagram b R2
+ Diagrams.Puzzles.Lib: phantom' :: Backend' b => Diagram b R2 -> Diagram b R2
- Diagrams.Puzzles.Lib: smash :: Backend b R2 => QDiagram b R2 Any -> QDiagram b R2 Any
+ Diagrams.Puzzles.Lib: smash :: Backend' b => QDiagram b R2 Any -> QDiagram b R2 Any
- Diagrams.Puzzles.Lib: spread :: Backend b R2 => R2 -> [Diagram b R2] -> Diagram b R2
+ Diagrams.Puzzles.Lib: spread :: Backend' b => R2 -> [Diagram b R2] -> Diagram b R2
- Diagrams.Puzzles.Lib: text' :: (Renderable (Path R2) b, Backend b R2) => String -> Diagram b R2
+ Diagrams.Puzzles.Lib: text' :: Backend' b => String -> Diagram b R2
- Diagrams.Puzzles.Lib: vline :: Renderable (Path R2) b => Double -> Diagram b R2
+ Diagrams.Puzzles.Lib: vline :: Backend' b => Double -> Diagram b R2
- Diagrams.Puzzles.PuzzleGrids: drawClueGrid :: (Backend b R2, Renderable (Path R2) b) => SGrid (Clue Char) -> Diagram b R2
+ Diagrams.Puzzles.PuzzleGrids: drawClueGrid :: Backend' b => SGrid (Clue Char) -> Diagram b R2
- Diagrams.Puzzles.PuzzleGrids: drawCompassClues :: (Backend b R2, Renderable (Path R2) b) => SGrid CompassClue -> Diagram b R2
+ Diagrams.Puzzles.PuzzleGrids: drawCompassClues :: Backend' b => SGrid CompassClue -> Diagram b R2
- Diagrams.Puzzles.PuzzleGrids: drawCompassGrid :: (Backend b R2, Renderable (Path R2) b) => SGrid CompassClue -> Diagram b R2
+ Diagrams.Puzzles.PuzzleGrids: drawCompassGrid :: Backend' b => SGrid CompassClue -> Diagram b R2
- Diagrams.Puzzles.PuzzleGrids: drawCrosses :: (Backend b R2, Renderable (Path R2) b) => SGrid Bool -> Diagram b R2
+ Diagrams.Puzzles.PuzzleGrids: drawCrosses :: Backend' b => SGrid Bool -> Diagram b R2
- Diagrams.Puzzles.PuzzleGrids: drawIntClues :: (Backend b R2, Renderable (Path R2) b) => SGrid (Clue Int) -> Diagram b R2
+ Diagrams.Puzzles.PuzzleGrids: drawIntClues :: Backend' b => SGrid (Clue Int) -> Diagram b R2
- Diagrams.Puzzles.PuzzleGrids: drawIntGrid :: (Backend b R2, Renderable (Path R2) b) => SGrid (Clue Int) -> Diagram b R2
+ Diagrams.Puzzles.PuzzleGrids: drawIntGrid :: Backend' b => SGrid (Clue Int) -> Diagram b R2
- Diagrams.Puzzles.PuzzleGrids: drawInts :: (Backend b R2, Renderable (Path R2) b) => SGrid Int -> Diagram b R2
+ Diagrams.Puzzles.PuzzleGrids: drawInts :: Backend' b => SGrid Int -> Diagram b R2
- Diagrams.Puzzles.PuzzleGrids: drawMasyuGrid :: (Backend b R2, Renderable (Path R2) b) => SGrid MasyuClue -> Diagram b R2
+ Diagrams.Puzzles.PuzzleGrids: drawMasyuGrid :: Backend' b => SGrid MasyuClue -> Diagram b R2
- Diagrams.Puzzles.PuzzleGrids: drawSlalomDiags :: (Backend b R2, Renderable (Path R2) b) => SGrid SlalomDiag -> Diagram b R2
+ Diagrams.Puzzles.PuzzleGrids: drawSlalomDiags :: Backend' b => SGrid SlalomDiag -> Diagram b R2
- Diagrams.Puzzles.PuzzleGrids: drawSlalomGrid :: (Backend b R2, Renderable (Path R2) b) => SGrid (Clue Int) -> Diagram b R2
+ Diagrams.Puzzles.PuzzleGrids: drawSlalomGrid :: Backend' b => SGrid (Clue Int) -> Diagram b R2
- Diagrams.Puzzles.PuzzleGrids: drawSlitherGrid :: (Backend b R2, Renderable (Path R2) b) => SGrid (Clue Int) -> Diagram b R2
+ Diagrams.Puzzles.PuzzleGrids: drawSlitherGrid :: Backend' b => SGrid (Clue Int) -> Diagram b R2
- Diagrams.Puzzles.PuzzleGrids: drawTightGrid :: (Backend b R2, Renderable (Path R2) b) => (t -> Diagram b R2) -> SGrid (Tightfit t) -> Diagram b R2
+ Diagrams.Puzzles.PuzzleGrids: drawTightGrid :: Backend' b => (t -> Diagram b R2) -> SGrid (Tightfit t) -> Diagram b R2
- Diagrams.Puzzles.PuzzleGrids: drawWordsClues :: (Backend b R2, Renderable (Path R2) b) => SGrid (Clue [String]) -> Diagram b R2
+ Diagrams.Puzzles.PuzzleGrids: drawWordsClues :: Backend' b => SGrid (Clue [String]) -> Diagram b R2
- Diagrams.Puzzles.PuzzleGrids: outsideGrid :: (Backend b R2, Renderable (Path R2) b) => OutsideClues [String] -> Diagram b R2
+ Diagrams.Puzzles.PuzzleGrids: outsideGrid :: Backend' b => OutsideClues [String] -> Diagram b R2
- Diagrams.Puzzles.PuzzleGrids: outsideIntGrid :: (Backend b R2, Renderable (Path R2) b) => OutsideClues [Int] -> Diagram b R2
+ Diagrams.Puzzles.PuzzleGrids: outsideIntGrid :: Backend' b => OutsideClues [Int] -> Diagram b R2
- Diagrams.Puzzles.PuzzleGrids: sudokugrid :: (Backend b R2, Renderable (Path R2) b) => SGrid a -> Diagram b R2
+ Diagrams.Puzzles.PuzzleGrids: sudokugrid :: Backend' b => SGrid a -> Diagram b R2
- Diagrams.Puzzles.PuzzleTypes: afternoonskyscrapers :: (Backend b R2, Renderable (Path R2) b) => RenderPuzzle b (SGrid Shade) IntGrid
+ Diagrams.Puzzles.PuzzleTypes: afternoonskyscrapers :: Backend' b => RenderPuzzle b (SGrid Shade) IntGrid
- Diagrams.Puzzles.PuzzleTypes: boxof2or3 :: (Backend b R2, Renderable (Path R2) b) => RenderPuzzle b (SGrid MasyuPearl, [Edge]) ()
+ Diagrams.Puzzles.PuzzleTypes: boxof2or3 :: Backend' b => RenderPuzzle b (SGrid MasyuPearl, [Edge]) ()
- Diagrams.Puzzles.PuzzleTypes: compass :: (Backend b R2, Renderable (Path R2) b) => RenderPuzzle b (SGrid (Clue CompassC)) AreaGrid
+ Diagrams.Puzzles.PuzzleTypes: compass :: Backend' b => RenderPuzzle b (SGrid (Clue CompassC)) AreaGrid
- Diagrams.Puzzles.PuzzleTypes: coral :: (Backend b R2, Renderable (Path R2) b) => RenderPuzzle b (OutsideClues [String]) ShadedGrid
+ Diagrams.Puzzles.PuzzleTypes: coral :: Backend' b => RenderPuzzle b (OutsideClues [String]) ShadedGrid
- Diagrams.Puzzles.PuzzleTypes: curvedata :: (Backend b R2, Renderable (Path R2) b) => RenderPuzzle b (SGrid (Clue [Edge])) [Edge]
+ Diagrams.Puzzles.PuzzleTypes: curvedata :: Backend' b => RenderPuzzle b (SGrid (Clue [Edge])) [Edge]
- Diagrams.Puzzles.PuzzleTypes: doubleback :: (Backend b R2, Renderable (Path R2) b) => RenderPuzzle b AreaGrid Loop
+ Diagrams.Puzzles.PuzzleTypes: doubleback :: Backend' b => RenderPuzzle b AreaGrid Loop
- Diagrams.Puzzles.PuzzleTypes: fillomino :: (Backend b R2, Renderable (Path R2) b) => RenderPuzzle b IntGrid IntGrid
+ Diagrams.Puzzles.PuzzleTypes: fillomino :: Backend' b => RenderPuzzle b IntGrid (SGrid Int)
- Diagrams.Puzzles.PuzzleTypes: geradeweg :: (Backend b R2, Renderable (Path R2) b) => RenderPuzzle b IntGrid Loop
+ Diagrams.Puzzles.PuzzleTypes: geradeweg :: Backend' b => RenderPuzzle b IntGrid Loop
- Diagrams.Puzzles.PuzzleTypes: japanesesums :: (Backend b R2, Renderable (Path R2) b) => RenderPuzzle b (OutsideClues [Int]) (SGrid JapVal)
+ Diagrams.Puzzles.PuzzleTypes: japanesesums :: Backend' b => RenderPuzzle b (OutsideClues [Int]) (SGrid (Either Black Int))
- Diagrams.Puzzles.PuzzleTypes: kpyramid :: (Backend b R2, Renderable (Path R2) b) => RenderPuzzle b RowKropkiPyramid PyramidSol
+ Diagrams.Puzzles.PuzzleTypes: kpyramid :: Backend' b => RenderPuzzle b RowKropkiPyramid PyramidSol
- Diagrams.Puzzles.PuzzleTypes: labyrinth :: (Backend b R2, Renderable (Path R2) b) => RenderPuzzle b (SGrid (Clue Int), [Edge]) (SGrid (Clue Int))
+ Diagrams.Puzzles.PuzzleTypes: labyrinth :: Backend' b => RenderPuzzle b (SGrid (Clue Int), [Edge]) (SGrid (Clue Int))
- Diagrams.Puzzles.PuzzleTypes: latintapa :: (Backend b R2, Renderable (Path R2) b) => RenderPuzzle b (SGrid (Clue [String])) CharClueGrid
+ Diagrams.Puzzles.PuzzleTypes: latintapa :: Backend' b => RenderPuzzle b (SGrid (Clue [String])) CharClueGrid
- Diagrams.Puzzles.PuzzleTypes: liarslither :: (Backend b R2, Renderable (Path R2) b) => RenderPuzzle b IntGrid (Loop, SGrid Bool)
+ Diagrams.Puzzles.PuzzleTypes: liarslither :: Backend' b => RenderPuzzle b IntGrid (Loop, SGrid Bool)
- Diagrams.Puzzles.PuzzleTypes: lits :: (Backend b R2, Renderable (Path R2) b) => RenderPuzzle b AreaGrid ShadedGrid
+ Diagrams.Puzzles.PuzzleTypes: lits :: Backend' b => RenderPuzzle b AreaGrid ShadedGrid
- Diagrams.Puzzles.PuzzleTypes: litsplus :: (Backend b R2, Renderable (Path R2) b) => RenderPuzzle b AreaGrid ShadedGrid
+ Diagrams.Puzzles.PuzzleTypes: litsplus :: Backend' b => RenderPuzzle b AreaGrid ShadedGrid
- Diagrams.Puzzles.PuzzleTypes: masyu :: (Backend b R2, Renderable (Path R2) b) => RenderPuzzle b (SGrid (Clue MasyuPearl)) Loop
+ Diagrams.Puzzles.PuzzleTypes: masyu :: Backend' b => RenderPuzzle b (SGrid (Clue MasyuPearl)) Loop
- Diagrams.Puzzles.PuzzleTypes: maximallengths :: (Backend b R2, Renderable (Path R2) b) => RenderPuzzle b (OutsideClues (Maybe Int)) Loop
+ Diagrams.Puzzles.PuzzleTypes: maximallengths :: Backend' b => RenderPuzzle b (OutsideClues (Maybe Int)) Loop
- Diagrams.Puzzles.PuzzleTypes: nurikabe :: (Backend b R2, Renderable (Path R2) b) => RenderPuzzle b IntGrid ShadedGrid
+ Diagrams.Puzzles.PuzzleTypes: nurikabe :: Backend' b => RenderPuzzle b IntGrid ShadedGrid
- Diagrams.Puzzles.PuzzleTypes: primeplace :: (Backend b R2, Renderable (Path R2) b) => RenderPuzzle b (SGrid PrimeDiag) (SGrid Int)
+ Diagrams.Puzzles.PuzzleTypes: primeplace :: Backend' b => RenderPuzzle b (SGrid PrimeDiag) (SGrid Int)
- Diagrams.Puzzles.PuzzleTypes: pyramid :: (Backend b R2, Renderable (Path R2) b) => RenderPuzzle b Pyramid PyramidSol
+ Diagrams.Puzzles.PuzzleTypes: pyramid :: Backend' b => RenderPuzzle b Pyramid PyramidSol
- Diagrams.Puzzles.PuzzleTypes: slalom :: (Backend b R2, Renderable (Path R2) b) => RenderPuzzle b IntGrid (SGrid SlalomDiag)
+ Diagrams.Puzzles.PuzzleTypes: slalom :: Backend' b => RenderPuzzle b IntGrid (SGrid SlalomDiag)
- Diagrams.Puzzles.PuzzleTypes: slither :: (Backend b R2, Renderable (Path R2) b) => RenderPuzzle b IntGrid Loop
+ Diagrams.Puzzles.PuzzleTypes: slither :: Backend' b => RenderPuzzle b IntGrid Loop
- Diagrams.Puzzles.PuzzleTypes: sudoku :: (Backend b R2, Renderable (Path R2) b) => RenderPuzzle b IntGrid IntGrid
+ Diagrams.Puzzles.PuzzleTypes: sudoku :: Backend' b => RenderPuzzle b IntGrid IntGrid
- Diagrams.Puzzles.PuzzleTypes: tapa :: (Backend b R2, Renderable (Path R2) b) => RenderPuzzle b (SGrid TapaClue) ShadedGrid
+ Diagrams.Puzzles.PuzzleTypes: tapa :: Backend' b => RenderPuzzle b (SGrid TapaClue) ShadedGrid
- Diagrams.Puzzles.PuzzleTypes: thermosudoku :: (Backend b R2, Renderable (Path R2) b) => RenderPuzzle b (SGrid Int, [Thermometer]) IntGrid
+ Diagrams.Puzzles.PuzzleTypes: thermosudoku :: Backend' b => RenderPuzzle b (SGrid Int, [Thermometer]) IntGrid
- Diagrams.Puzzles.PuzzleTypes: tightfitskyscrapers :: (Backend b R2, Renderable (Path R2) b) => RenderPuzzle b (OutsideClues (Maybe Int), SGrid (Tightfit ())) (SGrid (Tightfit Int))
+ Diagrams.Puzzles.PuzzleTypes: tightfitskyscrapers :: Backend' b => RenderPuzzle b (OutsideClues (Maybe Int), SGrid (Tightfit ())) (SGrid (Tightfit Int))
- Diagrams.Puzzles.PuzzleTypes: wordloop :: (Backend b R2, Renderable (Path R2) b) => RenderPuzzle b (CharClueGrid, [String]) CharClueGrid
+ Diagrams.Puzzles.PuzzleTypes: wordloop :: Backend' b => RenderPuzzle b (CharClueGrid, [String]) CharClueGrid
- Diagrams.Puzzles.PuzzleTypes: wordsearch :: (Backend b R2, Renderable (Path R2) b) => RenderPuzzle b (CharClueGrid, [String]) (CharClueGrid, [MarkedWord])
+ Diagrams.Puzzles.PuzzleTypes: wordsearch :: Backend' b => RenderPuzzle b (CharClueGrid, [String]) (CharClueGrid, [MarkedWord])
- Diagrams.Puzzles.Pyramid: cell :: (Backend b R2, Renderable (Path R2) b) => Bool -> Diagram b R2
+ Diagrams.Puzzles.Pyramid: cell :: Backend' b => Bool -> Diagram b R2
- Diagrams.Puzzles.Pyramid: cellc :: (Backend b R2, Renderable (Path R2) b) => Bool -> Maybe Int -> Diagram b R2
+ Diagrams.Puzzles.Pyramid: cellc :: Backend' b => Bool -> Maybe Int -> Diagram b R2
- Diagrams.Puzzles.Pyramid: clue :: (Backend b R2, Renderable (Path R2) b) => Maybe Int -> Diagram b R2
+ Diagrams.Puzzles.Pyramid: clue :: Backend' b => Maybe Int -> Diagram b R2
- Diagrams.Puzzles.Pyramid: kpyramid :: (Backend b R2, Renderable (Path R2) b) => RowKropkiPyramid -> Diagram b R2
+ Diagrams.Puzzles.Pyramid: kpyramid :: Backend' b => RowKropkiPyramid -> Diagram b R2
- Diagrams.Puzzles.Pyramid: kropki :: (Backend b R2, Renderable (Path R2) b) => KropkiDot -> Diagram b R2
+ Diagrams.Puzzles.Pyramid: kropki :: Backend' b => KropkiDot -> Diagram b R2
- Diagrams.Puzzles.Pyramid: krow :: (Backend b R2, Renderable (Path R2) b) => KropkiRow -> Diagram b R2
+ Diagrams.Puzzles.Pyramid: krow :: Backend' b => KropkiRow -> Diagram b R2
- Diagrams.Puzzles.Pyramid: pyramid :: (Backend b R2, Renderable (Path R2) b) => Pyramid -> Diagram b R2
+ Diagrams.Puzzles.Pyramid: pyramid :: Backend' b => Pyramid -> Diagram b R2
- Diagrams.Puzzles.Pyramid: row :: (Backend b R2, Renderable (Path R2) b) => Row -> Diagram b R2
+ Diagrams.Puzzles.Pyramid: row :: Backend' b => Row -> Diagram b R2
- Text.Puzzles.PuzzleTypes: fillomino :: ParsePuzzle IntGrid IntGrid
+ Text.Puzzles.PuzzleTypes: fillomino :: ParsePuzzle IntGrid (SGrid Int)
- Text.Puzzles.PuzzleTypes: japanesesums :: ParsePuzzle (OutsideClues [Int]) (SGrid JapVal)
+ Text.Puzzles.PuzzleTypes: japanesesums :: ParsePuzzle (OutsideClues [Int]) (SGrid (Either Black Int))

Files

CHANGES.md view
@@ -1,3 +1,15 @@+0.1.0.4: 20141115+-----------------++* add installation and usage instructions to README+* merge puzzle-draw-cmdline+* update for diagrams 1.2 and ghc 7.8+* add new puzzle types: Bahnhof, Cave+* rename `countnumbers` to `meanderingnumbers`+* include and use a nicer font+* command-line option to list supported puzzle types+* various tweaks and fixes+ 0.1.0.3: 20140519 ----------------- 
README.md view
@@ -3,14 +3,11 @@ puzzle-draw =========== -puzzle-draw is a library for drawing pencil puzzles using -[Diagrams][diagrams]. It aims to provide a utility layer on top of -Diagrams to help with drawing arbitrary puzzles, as well as supporting -several specific puzzle types directly. In addition, it includes -functionality for parsing puzzle data from a YAML file format.--See [puzzle-draw-cmdline][cmdline] for a command line tool that-uses this.+puzzle-draw is a library and command-line tool for drawing pencil+puzzles using [Diagrams][diagrams]. It aims to provide a utility layer+on top of Diagrams to help with drawing arbitrary puzzles, as well as+supporting several specific puzzle types directly. In addition, it+includes functionality for parsing puzzle data from a YAML file format.  Examples --------@@ -48,11 +45,59 @@     ..X... ``` +There is a demo web application at [demo] that provides some more+examples and that can be used to generate SVG images from such+puzzle descriptions.+ Or see a [puzzle set][twentyfour] that covers the puzzle types-that are supported currently.+that are supported as of 2014-05. -[travis]: http://travis-ci.org/robx/puzzle-draw-[cmdline]: http://github.com/robx/puzzle-draw-cmdline-[liarslither]: http://maybepuzzles.wordpress.com/types/liar-slither-link/-[twentyfour]: http://maybepuzzles.wordpress.com/2014/03/29/puzzle-set-24-hour-marathon/+Installing+----------++This is a brief overview of how to install the command line tool.+You'll need to get a Haskell environment, by installing the+[Haskell Platform][platform]. Then install `puzzle-draw` with cabal:++```+$ cabal install puzzle-draw+```++This will compile puzzle-draw against the SVG backend, and install+a binary `drawpuzzle` that formats puzzles to SVG. Alternatively,+you can compile against the Cairo backend by passing `-fcairo`:++```+$ cabal install -fcairo puzzle-draw+```++This will enable PDF and PNG output. Be warned that getting Cairo+installed can be tricky on non-Linux platforms.++Running+-------++As an example, suppose the Liar Slitherlink puzzle description above+is copied into a file `slitherliar.pzl`.++```+$ drawpuzzle slitherliar.pzl+```++This will generate two files `slitherliar.svg` and `slitherliar-sol.svg`,+containing the puzzle and solved puzzle, respectively. Run++```+$ drawpuzzle -h+```++to see some command line options that allow modifying the program's+behaviour, e.g., choosing the output format.++[travis]: https://travis-ci.org/robx/puzzle-draw+[cmdline]: https://github.com/robx/puzzle-draw-cmdline+[liarslither]: https://maybepuzzles.wordpress.com/types/liar-slither-link/+[twentyfour]: https://maybepuzzles.wordpress.com/2014/03/29/puzzle-set-24-hour-marathon/ [diagrams]: http://projects.haskell.org/diagrams/+[demo]: https://puzzle-draw-demo.herokuapp.com+[platform]: https://www.haskell.org/platform/
+ data/fonts/gen-light.svg view
@@ -0,0 +1,419 @@+<?xml version="1.0" standalone="no"?>+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >+<svg>+<metadata>+Created by FontForge 20120731 at Thu Nov  6 05:54:01 2014+ By Orthosie Webhosting+Gen Bold is a font by Alfredo Marco Pradil, designed in 2014.+</metadata>+<defs>+<font id="Gen-Light" horiz-adv-x="500" >+  <font-face +    font-family="Gen Light"+    font-weight="300"+    font-stretch="normal"+    units-per-em="1000"+    panose-1="0 0 0 0 0 0 0 0 0 0"+    ascent="800"+    descent="-200"+    x-height="502"+    cap-height="725"+    bbox="-25 -230 991 957"+    underline-thickness="50"+    underline-position="-50"+    unicode-range="U+000D-2122"+  />+<missing-glyph horiz-adv-x="250" + />+    <glyph glyph-name=".notdef" horiz-adv-x="250" + />+    <glyph glyph-name="NULL" horiz-adv-x="0" + />+    <glyph glyph-name="NULL" horiz-adv-x="0" + />+    <glyph glyph-name="nonmarkingreturn" unicode="&#xd;" horiz-adv-x="250" + />+    <glyph glyph-name="space" unicode=" " horiz-adv-x="250" + />+    <glyph glyph-name="numbersign" unicode="#" horiz-adv-x="560" +d="M405 224v-204h-43v204h-151v-204h-42v204h-98v45h98v155h-98v44h98v204h42v-204h151v204h43v-204h98v-44h-98v-155h98v-45h-98zM362 424h-151v-155h151v155z" />+    <glyph glyph-name="dollar" unicode="$" horiz-adv-x="565" +d="M296 -68h-40v53q-43 2 -81 13.5t-66.5 33.5t-45 55t-16.5 78v4h60q2 -67 42.5 -98t106.5 -35v287q-43 15 -79 30t-62 37t-40.5 54t-14.5 82q0 36 17 68.5t44.5 57.5t62.5 39.5t72 14.5v49h40v-49q40 0 75 -11.5t62 -33.5t44 -52.5t21 -69.5h-60q-1 30 -13 51.5t-31 36+t-44.5 22t-53.5 9.5v-287q37 -11 75.5 -25.5t69 -36.5t50 -52.5t19.5 -74.5q0 -96 -59 -146t-155 -50v-54zM256 656q-30 0 -55 -11.5t-43 -30.5t-28 -44t-10 -53q0 -31 11.5 -52.5t30 -37t43 -26t51.5 -18.5v273zM296 36q30 2 57.5 12t49 27t34.5 41t13 56q0 34 -13.5 57+t-35.5 39.5t-49.5 27.5t-55.5 20v-280z" />+    <glyph glyph-name="percent" unicode="%" horiz-adv-x="900" +d="M401 518q0 24 -5.5 49.5t-18 46.5t-32.5 34.5t-48 13.5q-29 0 -49 -13t-32 -34t-17.5 -46.5t-5.5 -50.5t5.5 -50.5t17.5 -46.5t32 -34t49 -13q28 0 48 13.5t32.5 34.5t18 46.5t5.5 49.5zM673 707h58l-390 -707h-58zM138 518q0 36 10 70t30.5 60.5t50 42.5t68.5 16+t68.5 -16t50 -42.5t30.5 -60.5t10 -70t-10 -70t-30 -60.5t-49.5 -42.5t-69.5 -16q-39 0 -69 16t-50 42.5t-30 60.5t-10 70zM544 174q0 36 10 70t30.5 60.5t50 42.5t68.5 16t68.5 -16t50 -42.5t30.5 -60.5t10 -70t-10 -70t-30 -60.5t-49.5 -42.5t-69.5 -16q-39 0 -69 16+t-50 42.5t-30 60.5t-10 70zM807 174q0 24 -5.5 49.5t-18 46.5t-32.5 34.5t-48 13.5q-29 0 -49 -13t-32 -34t-17.5 -46.5t-5.5 -50.5t5.5 -50.5t17.5 -46.5t32 -34t49 -13q28 0 48 13.5t32.5 34.5t18 46.5t5.5 49.5z" />+    <glyph glyph-name="ampersand" unicode="&#x26;" horiz-adv-x="720" +d="M264 44q34 0 61 14t49.5 36t41 48.5t35.5 51.5l-176 187q-26 -17 -53 -41t-48.5 -53.5t-35 -62t-13.5 -65.5q0 -29 12 -50.5t31.5 -35.5t44.5 -21.5t51 -7.5zM209 591q0 -20 7.5 -37.5t19 -34t25.5 -31t26 -27.5q16 15 34 27t33 26t24.5 32t9.5 45q0 18 -8 33.5t-21.5 27+t-30 18.5t-33.5 7q-35 0 -60.5 -25.5t-25.5 -60.5zM233 422q-16 19 -32.5 38t-30 39t-22.5 43t-9 49q0 31 13.5 58t35.5 46.5t50.5 30.5t58.5 11t59 -10.5t51.5 -30t36.5 -46.5t14 -59q0 -31 -12 -56t-31.5 -45t-43 -37.5t-45.5 -33.5l158 -171l95 160h74l-128 -204+l193 -204h-93l-134 150q-25 -37 -46.5 -67.5t-47 -52t-59 -33.5t-82.5 -12q-38 0 -73.5 12t-64 34t-45.5 54t-17 73t15.5 79.5t40.5 72.5t57 62.5t64 49.5z" />+    <glyph glyph-name="quotesingle" unicode="'" horiz-adv-x="226" +d="M87 496v226h52v-226h-52z" />+    <glyph glyph-name="parenleft" unicode="(" horiz-adv-x="266" +d="M183 -96q-2 7 -8 23t-16 41t-16 42.5t-10 27.5t-9 26t-12 38t-12 40t-8 32q-5 28 -10.5 66.5t-5.5 72.5q0 64 16 135q8 37 17 67.5t17 53.5t20.5 55.5t28.5 74.5l9 23h50q-88 -225 -88 -409t88 -409h-51z" />+    <glyph glyph-name="parenright" unicode=")" horiz-adv-x="275" +d="M44 -96q88 225 88 409t-88 409h50q35 -91 57 -155t32 -103q19 -79 19 -151q0 -34 -6 -73q-3 -19 -5 -34.5t-5.5 -31.5t-8 -33t-11.5 -39t-12 -38t-9 -26t-10 -27.5t-16 -42.5t-16 -41t-8 -23h-51z" />+    <glyph glyph-name="asterisk" unicode="*" horiz-adv-x="475" +d="M116 567h131l-66 114l31 17l66 -113l65 113l31 -17l-66 -114h131v-35h-131l66 -114l-31 -18l-65 114l-66 -114l-31 18l66 114h-131v35z" />+    <glyph glyph-name="plus" unicode="+" horiz-adv-x="595" +d="M568 332h-220v-221h-36v221h-220v36h220v221h36v-221h220v-36z" />+    <glyph glyph-name="comma" unicode="," horiz-adv-x="240" +d="M102 81h81l-72 -205h-52z" />+    <glyph glyph-name="hyphen" unicode="-" horiz-adv-x="322" +d="M253 333h-228v36h228v-36z" />+    <glyph glyph-name="period" unicode="." horiz-adv-x="242" +d="M179 0h-80v86h80v-86z" />+    <glyph glyph-name="slash" unicode="/" horiz-adv-x="553" +d="M503 707l-405 -707h-48l407 707h46z" />+    <glyph glyph-name="zero" unicode="0" horiz-adv-x="570" +d="M445 346q0 27 -1.5 60t-7 66t-16 65t-28.5 56t-44 39t-63 15t-63 -15t-44 -39t-28.5 -56t-16 -65t-7 -66t-1.5 -60t1.5 -60t7 -66t16 -65t28.5 -56t44 -39t63 -15t63 15t44 39t28.5 56t16 65t7 66t1.5 60zM55 346q0 58 8 121.5t32.5 117t70 88t119.5 34.5t119.5 -34.5+t70 -88t32.5 -117t8 -121.5t-8 -121.5t-32.5 -117t-70 -88t-119.5 -34.5t-119.5 34.5t-70 88t-32.5 117t-8 121.5z" />+    <glyph glyph-name="one" unicode="1" horiz-adv-x="570" +d="M175 583l159 109h62v-692h-65v624l-128 -84z" />+    <glyph glyph-name="two" unicode="2" horiz-adv-x="570" +d="M503 0h-435v68q23 22 59 55.5t75.5 73.5t79 84.5t71 88t51.5 83.5t20 71q0 30 -11.5 53t-30.5 38.5t-44 23.5t-53 8q-30 0 -56 -10t-44.5 -28t-29 -43.5t-10.5 -56.5h-70q0 46 16 83t44.5 62.5t66.5 39t83 13.5q44 0 82 -12.5t66.5 -37t44.5 -60.5t16 -82q0 -36 -19 -77+t-50 -84t-69 -86t-77 -81.5t-74 -71t-59 -55.5h357v-60z" />+    <glyph glyph-name="three" unicode="3" horiz-adv-x="570" +d="M206 392q33 0 73.5 3.5t75.5 16.5t58.5 39t23.5 71q0 30 -14 53.5t-36 39.5t-49.5 24.5t-54.5 8.5q-29 0 -55 -8.5t-46 -25t-33 -40t-16 -53.5h-70q0 45 19 80t50 58.5t71 36t81 12.5q42 0 82 -12.5t71.5 -36.5t50.5 -59.5t19 -81.5q0 -32 -15 -58t-38 -45.5t-51.5 -33+t-56.5 -19.5v-2q31 -7 62 -22t55.5 -37t39.5 -51.5t15 -64.5q0 -49 -21 -86t-55 -62.5t-77 -38.5t-87 -13t-84.5 13.5t-71 39t-49.5 62t-20 83.5h70q0 -33 13.5 -59t36.5 -43.5t52 -26.5t60 -9q33 0 63 10t52 29t35 46.5t13 62.5q0 46 -25 73t-62 41t-79 18t-76 4v63z" />+    <glyph glyph-name="four" unicode="4" horiz-adv-x="570" +d="M360 0v161h-325v63l304 468h86v-477h111v-54h-111v-161h-65zM360 215v412h-2l-268 -412h270z" />+    <glyph glyph-name="five" unicode="5" horiz-adv-x="570" +d="M62 291v401h411v-60h-341v-249q28 33 68.5 53t85.5 20q49 0 90.5 -18t70.5 -49t45.5 -73t16.5 -91q0 -48 -16 -91.5t-45.5 -76.5t-70.5 -52.5t-91 -19.5q-44 0 -84.5 10.5t-71 33t-49 57.5t-19.5 84h70q1 -31 13.5 -54.5t32.5 -39t46 -23.5t55 -8q37 0 67 14.5t51 39+t32.5 56.5t11.5 68t-11.5 67.5t-32.5 55t-51 37t-67 13.5q-24 0 -48 -7t-44.5 -20.5t-35 -33t-19.5 -44.5h-70z" />+    <glyph glyph-name="six" unicode="6" horiz-adv-x="570" +d="M300 394q-41 0 -72 -14.5t-52 -39t-31.5 -58t-10.5 -71.5q0 -34 13.5 -64t36 -52.5t52.5 -36t64 -13.5q38 0 66 12.5t46 34.5t27 52.5t9 66.5q0 34 -8.5 67t-26.5 59t-46 41.5t-67 15.5zM300 707q41 0 78.5 -11t66.5 -33t46 -55t18 -78h-70q-1 27 -13 49t-31.5 37+t-44.5 23t-50 8q-63 0 -98.5 -31t-53 -77.5t-22 -101t-4.5 -101.5h2q24 58 69.5 85.5t106.5 27.5q53 0 94 -18.5t68.5 -50.5t41.5 -75.5t14 -93.5t-15 -91.5t-43 -71.5t-68.5 -46.5t-91.5 -16.5q-73 0 -120.5 27.5t-76 73t-40 104.5t-11.5 121q0 43 3 89.5t11.5 90.5+t25.5 83t44.5 69t67.5 47t96 17z" />+    <glyph glyph-name="seven" unicode="7" horiz-adv-x="570" +d="M506 692v-60l-269 -632h-76l277 632h-373v60h441z" />+    <glyph glyph-name="eight" unicode="8" horiz-adv-x="570" +d="M201 361q-32 4 -58 17.5t-44.5 35t-28.5 49.5t-10 60q0 46 19.5 81t51.5 57.5t72 34t82 11.5q41 0 81.5 -12t72.5 -35t52 -57.5t20 -80.5q0 -31 -11 -57.5t-30 -47.5t-44.5 -35.5t-54.5 -20.5v-1q31 -8 58.5 -23.5t48 -37t32.5 -50t12 -61.5q0 -48 -20.5 -85.5t-54 -64+t-76 -40t-86.5 -13.5t-86.5 13t-75.5 38.5t-53.5 62.5t-20.5 85q0 34 11.5 63t32 51.5t48.5 38t60 22.5v2zM123 520q0 -33 14 -57.5t37 -40.5t52 -23.5t59 -7.5q29 0 58 7.5t52 23.5t37.5 40.5t14.5 57.5t-14.5 57.5t-37.5 41t-52 25t-58 8.5q-30 0 -59 -8.5t-52 -25+t-37 -41t-14 -57.5zM285 331q-33 0 -63 -9t-53 -27t-36.5 -45t-13.5 -62q0 -36 13.5 -62.5t36.5 -44.5t53 -27t63 -9q32 0 62 9t53.5 27t37.5 44.5t14 62.5q0 35 -14 61.5t-37.5 44.5t-53.5 27.5t-62 9.5z" />+    <glyph glyph-name="nine" unicode="9" horiz-adv-x="570" +d="M274 647q-39 0 -67.5 -13t-47 -36.5t-28 -54.5t-9.5 -67q0 -34 11 -62.5t30.5 -49t47.5 -32t63 -11.5t65 10.5t51.5 30.5t34 49t12.5 65q0 83 -39 127t-124 44zM124 170q1 -32 13.5 -55t33 -39t47.5 -23.5t56 -7.5q38 0 66 14t47.5 37.5t31.5 54.5t18.5 64.5t9 67+t2.5 62.5v27h-2q-55 -106 -173 -106q-47 0 -87.5 15t-70.5 42.5t-47 66t-17 86.5q0 49 15.5 91.5t44.5 73.5t70 48.5t92 17.5q78 0 126 -29.5t74.5 -77.5t35.5 -109.5t9 -125.5q0 -41 -4 -85t-14 -86.5t-27.5 -80t-44.5 -66t-65.5 -45.5t-89.5 -17q-44 0 -82.5 11.5t-68 35+t-47.5 58t-22 80.5h70z" />+    <glyph glyph-name="colon" unicode=":" horiz-adv-x="230" +d="M99 502h80v-86h-80v86zM99 86h80v-86h-80v86z" />+    <glyph glyph-name="semicolon" unicode=";" horiz-adv-x="254" +d="M121 81h81l-72 -205h-52zM107 502h80v-86h-80v86z" />+    <glyph glyph-name="less" unicode="&#x3c;" horiz-adv-x="613" +d="M159 251l421 -197v-64l-500 235v53l500 223v-64z" />+    <glyph glyph-name="equal" unicode="=" horiz-adv-x="602" +d="M580 378v-60h-500v60h500zM580 184v-60h-500v60h500z" />+    <glyph glyph-name="greater" unicode="&#x3e;" horiz-adv-x="599" +d="M501 251l-421 197v64l500 -235v-53l-500 -223v64z" />+    <glyph glyph-name="question" unicode="?" horiz-adv-x="464" +d="M425 556q0 -38 -14 -68t-35.5 -56t-46 -49t-46 -45.5t-35.5 -46.5t-14 -52v-70h-60v70q0 34 14 61t34.5 51t44.5 46t44.5 46t34.5 51t14 62q0 54 -28 87.5t-84 33.5q-51 0 -90 -16t-75 -53l-50 38q44 48 98 69.5t117 21.5q87 0 132 -47.5t45 -133.5zM164 86h80v-86h-80+v86z" />+    <glyph glyph-name="at" unicode="@" horiz-adv-x="808" +d="M430 525q-37 0 -68.5 -22.5t-55 -57t-36.5 -75t-12 -76.5q2 -45 20 -70.5t56 -27.5q28 -1 57 25t53 64t39 81t14 78q-1 37 -17 58.5t-50 22.5zM554 566h66l-100 -300q-12 -35 -12 -51q0 -24 29 -26q29 -1 57.5 21.5t51 58t36 77.5t12.5 81q-2 118 -83 188q-83 72 -199 72+q-136 0 -224 -97q-88 -95 -88 -233q0 -135 89 -229q90 -93 223 -93q78 0 149.5 35.5t117.5 99.5h58q-47 -86 -136 -135q-89 -50 -189 -50q-159 0 -266 107q-106 107 -106 265q0 169 108 274q107 106 264 106q143 0 243 -89q99 -89 99 -224q0 -113 -74 -202q-73 -88 -157 -88+q-29 0 -53 13.5t-32 38.5q-50 -50 -119 -50t-102.5 43t-33.5 110q0 49 17.5 101t50 95.5t77.5 71.5t100 28q36 0 66 -17t45 -48z" />+    <glyph glyph-name="A" unicode="A" horiz-adv-x="668" +d="M173 255h315l-156 407zM76 0h-67l286 722h76l288 -722h-71l-77 195h-359z" />+    <glyph glyph-name="B" unicode="B" horiz-adv-x="665" +d="M165 404h120q36 0 67.5 4.5t55.5 18.5t38 40t14 68q0 61 -40 94t-111 33h-144v-258zM100 0v722h209q41 0 81 -9.5t71 -31t50 -57.5t19 -89q0 -21 -5.5 -45.5t-18 -47t-32.5 -40t-48 -24.5v-2q35 -6 65 -21.5t52 -39t34.5 -54.5t12.5 -68q0 -52 -18.5 -88.5t-50.5 -60+t-74 -34t-88 -10.5h-259zM165 344v-284h154q34 0 69.5 5t64.5 19t48 40.5t19 68.5q0 54 -21 84t-55 45t-75.5 18.5t-83.5 3.5h-120z" />+    <glyph glyph-name="C" unicode="C" horiz-adv-x="667" +d="M549 560q-8 31 -25.5 53t-41 36.5t-52 21t-59.5 6.5q-71 0 -117 -26.5t-74 -71t-39 -101.5t-11 -117q0 -59 12 -115.5t40.5 -101t74.5 -72t114 -27.5q31 0 60.5 9.5t53.5 27.5t41 44t23 58h70q-8 -45 -31 -81.5t-57 -63t-75.5 -40.5t-84.5 -14q-83 0 -142 31t-96.5 83+t-55 120t-17.5 142q0 76 17 144t54 119.5t96 82t144 30.5q91 0 157 -44.5t91 -132.5h-70z" />+    <glyph glyph-name="D" unicode="D" horiz-adv-x="722" +d="M155 60h102q60 0 119 11t106 43.5t76 91.5t29 155q0 94 -32.5 152.5t-82 91.5t-107 45t-108.5 12h-102v-602zM90 722h167q41 0 87 -6.5t90.5 -22t85 -41.5t71 -66t48.5 -95.5t18 -129.5q0 -75 -16.5 -131t-45.5 -96t-68 -66t-83.5 -41t-92 -21t-94.5 -6h-167v722z" />+    <glyph glyph-name="E" unicode="E" horiz-adv-x="609" +d="M544 0h-444v722h424v-60h-359v-259h340v-60h-340v-283h379v-60z" />+    <glyph glyph-name="F" unicode="F" horiz-adv-x="578" +d="M160 0h-65v722h428v-60h-363v-255h343v-60h-343v-347z" />+    <glyph glyph-name="G" unicode="G" horiz-adv-x="725" +d="M376 368h259v-278q0 -28 -29.5 -48t-69 -32.5t-79.5 -18.5t-61 -6q-80 0 -141.5 30t-103.5 80.5t-64 117.5t-22 142q0 68 20 136.5t59.5 123t97.5 88.5t134 34q44 0 87.5 -12t79.5 -36.5t59.5 -60.5t27.5 -84h-74q-5 34 -21.5 59t-41.5 41.5t-55.5 24.5t-61.5 8+q-62 0 -107 -28.5t-74.5 -73.5t-43.5 -100.5t-14 -109.5q0 -59 15.5 -116.5t48 -102.5t81 -73t114.5 -28q14 0 43 4t58 12.5t51 21.5t22 32v193h-194v60z" />+    <glyph glyph-name="H" unicode="H" horiz-adv-x="724" +d="M165 0h-65v722h65v-317h394v317h65v-722h-65v345h-394v-345z" />+    <glyph glyph-name="I" unicode="I" horiz-adv-x="245" +d="M155 0h-65v725h65v-725z" />+    <glyph glyph-name="J" unicode="J" horiz-adv-x="504" +d="M85 178q2 -25 10 -49t22 -42.5t34.5 -30t49.5 -11.5q43 0 72 14t45.5 38t23.5 57t7 71v497h65v-497q0 -51 -13 -95t-39 -76.5t-66 -50.5t-95 -18q-42 0 -75 15.5t-56.5 41.5t-37 61.5t-17.5 74.5h70z" />+    <glyph glyph-name="K" unicode="K" horiz-adv-x="610" +d="M169 0h-64v722h64v-343l303 343h82l-308 -346l359 -376h-89l-347 377v-377z" />+    <glyph glyph-name="L" unicode="L" horiz-adv-x="528" +d="M528 0h-428v722h65v-662h363v-60z" />+    <glyph glyph-name="M" unicode="M" horiz-adv-x="951" +d="M165 0h-65v722h104l271 -629l277 629h99v-722h-65v667h-2l-276 -667h-65l-276 664h-2v-664z" />+    <glyph glyph-name="N" unicode="N" horiz-adv-x="719" +d="M90 0v722h74l398 -635h2v635h65v-722h-82l-390 624h-2v-624h-65z" />+    <glyph glyph-name="O" unicode="O" horiz-adv-x="774" +d="M387 677q-68 0 -116 -27.5t-78 -72.5t-44 -102t-14 -117q0 -59 14.5 -115t45.5 -100t78.5 -71t113.5 -27q68 0 116 28t78 73t44 102.5t14 117.5q0 58 -14.5 114t-45.5 100t-78.5 70.5t-113.5 26.5zM387 737q83 0 144 -30t100.5 -81.5t58.5 -120t19 -144.5t-19 -144.5+t-58.5 -120t-100.5 -81.5t-144 -30q-84 0 -144.5 30t-100 81.5t-58.5 119.5t-19 145q0 76 19 144.5t58.5 120t100 81.5t144.5 30z" />+    <glyph glyph-name="P" unicode="P" horiz-adv-x="611" +d="M165 662v-288h158q37 0 70.5 6.5t58.5 23t39.5 44.5t14.5 70t-14.5 69.5t-39.5 44t-58.5 23.5t-70.5 7h-158zM165 0h-65v722h181q52 0 105 -8t95 -30.5t68.5 -62t26.5 -103.5q0 -56 -19.5 -93t-52.5 -59.5t-75 -33.5t-88 -15t-91.5 -3.5t-84.5 0.5v-314z" />+    <glyph glyph-name="Q" unicode="Q" horiz-adv-x="810" +d="M735 -80q-20 14 -41 30.5t-42.5 30.5t-45.5 23.5t-50 9.5q-21 0 -41.5 -4.5t-40.5 -10t-40 -10t-41 -4.5q-79 0 -140 31.5t-102 83.5t-62.5 120t-21.5 141t21.5 141t62.5 120t102 83.5t140 31.5t139.5 -30t101.5 -81t62 -118t21 -140q0 -43 -7.5 -87t-24 -85.5+t-41.5 -77.5t-61 -63l2 -2q26 3 50.5 -4t47 -20t44 -28.5t41.5 -28.5zM647 361q0 57 -15.5 113.5t-47 101.5t-79.5 73t-112 28q-65 0 -112.5 -28t-79 -73.5t-47 -102t-15.5 -113.5t15.5 -113.5t47 -101t79.5 -72.5t112 -28q65 0 112.5 28t79 73t47 101.5t15.5 113.5z" />+    <glyph glyph-name="R" unicode="R" horiz-adv-x="660" +d="M165 404h147q39 0 74.5 4t63 18t44 41t16.5 74q0 37 -15 60.5t-39 37t-54.5 18.5t-60.5 5h-176v-258zM165 344v-344h-65v722h204q51 0 100.5 -6t88.5 -25.5t63 -57t24 -100.5q0 -31 -12 -59t-32.5 -49.5t-47.5 -36t-57 -17.5v-2q51 -15 81 -60t47 -101t25 -112.5+t16 -95.5h-66q-8 44 -14 86.5t-14 80.5t-20.5 70.5t-35 56t-58 37t-88.5 13.5h-139z" />+    <glyph glyph-name="S" unicode="S" horiz-adv-x="615" +d="M555 179q0 -52 -20.5 -89.5t-54.5 -62t-77.5 -36t-89.5 -11.5q-51 0 -96.5 10.5t-80 34.5t-55 63t-21.5 95h70q1 -41 15.5 -69t38.5 -45t56.5 -24.5t70.5 -7.5q36 0 68 7t55.5 23.5t37 43.5t13.5 68q0 49 -30 77t-75.5 46.5t-98.5 34t-98.5 39t-75.5 61t-30 100.5+q0 47 20 83.5t52 61t73.5 37.5t84.5 13t83 -9t72 -29.5t53 -53.5t27 -80h-70q-1 33 -16.5 55t-39 35.5t-52.5 19t-57 5.5q-31 0 -60 -7t-51 -22.5t-35.5 -40t-13.5 -59.5q0 -51 30 -81t75.5 -50t98.5 -36t98.5 -39.5t75.5 -61t30 -99.5z" />+    <glyph glyph-name="T" unicode="T" horiz-adv-x="558" +d="M249 0l-1 662h-233v60h528v-60h-229l-1 -662h-64z" />+    <glyph glyph-name="U" unicode="U" horiz-adv-x="728" +d="M100 722h65v-467q0 -45 13.5 -83.5t39 -66.5t62.5 -44t84 -16t84 16t62.5 44t39 66.5t13.5 83.5v467h65v-468q0 -61 -18 -110.5t-52 -85t-83 -54.5t-111 -19t-111 19t-83 54.5t-52 85t-18 110.5v468z" />+    <glyph glyph-name="V" unicode="V" horiz-adv-x="619" +d="M81 722l232 -657h2l229 657h65l-261 -722h-74l-264 722h71z" />+    <glyph glyph-name="W" unicode="W" horiz-adv-x="1001" +d="M497 655l-207 -655h-92l-188 722h69l168 -657h2l211 657h79l220 -657h2l167 657h63l-190 -722h-89l-213 655h-2z" />+    <glyph glyph-name="X" unicode="X" horiz-adv-x="611" +d="M301 323l-219 -323h-74l257 372l-244 350h85l204 -304l212 304h73l-250 -350l258 -372h-83z" />+    <glyph glyph-name="Y" unicode="Y" horiz-adv-x="615" +d="M276 0v312l-266 410h83l221 -349l221 349h70l-264 -408v-314h-65z" />+    <glyph glyph-name="Z" unicode="Z" horiz-adv-x="535" +d="M517 0h-478v60l401 602h-401v60h478v-60l-402 -602h402v-60z" />+    <glyph glyph-name="bracketleft" unicode="[" horiz-adv-x="260" +d="M222 -46h-137v818h137v-50h-80v-718h80v-50z" />+    <glyph glyph-name="backslash" unicode="\" horiz-adv-x="445" +d="M352 0l-302 722h43l302 -722h-43z" />+    <glyph glyph-name="bracketright" unicode="]" horiz-adv-x="278" +d="M56 772h137v-818h-137v50h80v718h-80v50z" />+    <glyph glyph-name="asciicircum" unicode="^" horiz-adv-x="626" +d="M132 239h-58l230 453h52l231 -453h-57l-201 392z" />+    <glyph glyph-name="underscore" unicode="_" horiz-adv-x="467" +d="M500 -124h-500v56h500v-56z" />+    <glyph glyph-name="grave" unicode="`" horiz-adv-x="229" +d="M20 707h80l91 -143h-44z" />+    <glyph glyph-name="a" unicode="a" horiz-adv-x="494" +d="M101 140q0 -49 29.5 -74.5t72.5 -25.5q27 0 55.5 8t52 23t38.5 36.5t15 48.5v81h-44h-57t-73 -8t-62.5 -28.5t-26.5 -60.5zM36 140q0 42 16 69.5t42.5 44.5t60.5 25t70.5 11t72.5 2.5t66 -0.5q0 37 -2.5 68.5t-15 54t-38.5 35t-72 12.5q-57 0 -90.5 -32.5t-33.5 -82.5+h-64q0 39 15.5 70.5t41.5 53.5t60 34t72 12q96 0 141.5 -44.5t45.5 -121.5v-351h-59v74h-2q-10 -23 -27.5 -39.5t-39 -27.5t-46 -16.5t-47.5 -5.5q-35 0 -65.5 10.5t-53 30.5t-35.5 49t-13 65z" />+    <glyph glyph-name="b" unicode="b" horiz-adv-x="551" +d="M299 462q-44 0 -76.5 -18t-55 -48t-33.5 -68t-11 -77t11 -77t33.5 -68t55 -48t76.5 -18q39 0 66.5 22t45 54.5t25 70.5t7.5 70q0 33 -7.5 69t-24.5 66.5t-44.5 50t-67.5 19.5zM125 78v-78h-60v722h60v-296h2q26 45 73.5 68t98.5 23q52 0 91 -23.5t65 -61t38.5 -84.5+t12.5 -93t-12.5 -94t-38 -87t-64.5 -64t-92 -25q-55 0 -98 24t-74 69h-2z" />+    <glyph glyph-name="c" unicode="c" +d="M397 348q-4 62 -42 88t-95 26q-43 0 -71.5 -19.5t-46 -50t-24.5 -67.5t-7 -73q0 -33 8 -70.5t26 -69t46 -52t69 -20.5q27 0 51 8t42.5 23t30 36.5t13.5 49.5h65q-24 -172 -196 -172q-57 0 -98.5 22.5t-68.5 59.5t-40 85t-13 99q0 54 12.5 102.5t39.5 84.5t69.5 57.5+t102.5 21.5q38 0 72 -11.5t60 -33t42 -53t18 -71.5h-65z" />+    <glyph glyph-name="d" unicode="d" horiz-adv-x="551" +d="M252 40q43 0 76 18.5t54.5 48.5t32.5 68t11 77t-11 76.5t-33 67.5t-54.5 48t-75.5 18q-40 0 -67.5 -20.5t-44.5 -51.5t-24.5 -67.5t-7.5 -69.5t7.5 -70t24.5 -69t44.5 -53t67.5 -21zM426 0v78h-2q-31 -45 -74 -69t-98 -24q-53 0 -92 24.5t-64.5 63.5t-38 87t-12.5 94+q0 47 12 94t37.5 84.5t64.5 61t93 23.5q51 0 98.5 -23t73.5 -68h2v296h60v-722h-60z" />+    <glyph glyph-name="e" unicode="e" horiz-adv-x="568" +d="M115 237q1 -41 9.5 -77t28 -62.5t50.5 -42t77 -15.5q27 0 52 9t45.5 25t35.5 38t21 48h63q-22 -85 -75 -130t-142 -45q-55 0 -98.5 21t-73.5 56.5t-45.5 82.5t-15.5 99q0 49 15 98t44 88t71 63t97 24q64 0 108 -22.5t71 -60.5t38.5 -89t11.5 -108h-388zM438 292+q-3 36 -14 67.5t-31 54t-49.5 35.5t-68.5 13q-36 0 -64.5 -14t-48 -37.5t-31 -54.5t-14.5 -64h321z" />+    <glyph glyph-name="f" unicode="f" horiz-adv-x="333" +d="M183 0h-60v447h-101v55h101q0 39 -2 80.5t6.5 75t34.5 55t82 21.5q14 0 28.5 -3.5t28.5 -7.5l-12 -49q-30 7 -50.5 6.5t-33 -10.5t-17.5 -30t-5 -51v-87h106v-55h-106v-447z" />+    <glyph glyph-name="g" unicode="g" horiz-adv-x="551" +d="M259 57q42 0 73.5 17t52.5 45t31.5 64t10.5 74q0 37 -10.5 73.5t-31.5 66t-52.5 47.5t-73.5 18q-40 0 -68 -19.5t-46 -50t-26.5 -67t-8.5 -69.5q0 -34 8 -69.5t26 -64t46.5 -47t68.5 -18.5zM426 424v78h60v-455q0 -119 -52 -179t-175 -60q-32 0 -66 6.5t-62 22t-46 41.5+t-18 65h65q3 -24 15.5 -39.5t30.5 -24.5t39 -12.5t42 -3.5q32 0 62 8.5t53.5 25.5t37.5 43.5t14 61.5v94h-2q-23 -45 -69.5 -69.5t-95.5 -24.5q-52 0 -92.5 21.5t-68 57.5t-42 81.5t-14.5 93.5t14 94.5t41.5 83.5t68 60t93.5 23q52 0 94 -25.5t71 -67.5h2z" />+    <glyph glyph-name="h" unicode="h" horiz-adv-x="556" +d="M140 722v-296h2q52 91 157 91q49 0 83 -16.5t55 -45.5t30 -68t9 -83v-304h-60v304q0 29 -5.5 57.5t-19 51t-36 36t-56.5 13.5q-72 0 -115.5 -42.5t-43.5 -115.5v-304h-60v722h60z" />+    <glyph glyph-name="i" unicode="i" horiz-adv-x="220" +d="M80 502h60v-502h-60v502zM145 722v-75h-70v75h70z" />+    <glyph glyph-name="j" unicode="j" horiz-adv-x="223" +d="M43 -137q14 0 22 4.5t11.5 12t4.5 17.5t1 22l-1 583h61v-568q0 -32 -2 -56t-12 -39.5t-29.5 -23t-55.5 -7.5v55zM146 722v-75h-70v75h70z" />+    <glyph glyph-name="k" unicode="k" +d="M145 722v-446l257 226h77l-259 -230l265 -272h-76l-264 272v-272h-60v722h60z" />+    <glyph glyph-name="l" unicode="l" horiz-adv-x="220" +d="M140 722v-722h-60v722h60z" />+    <glyph glyph-name="m" unicode="m" horiz-adv-x="887" +d="M135 502v-76h2q26 46 68 68.5t94 22.5q55 0 97.5 -28.5t60.5 -81.5q29 46 75.5 78t102.5 32q55 0 89 -18.5t52.5 -49.5t24.5 -73t6 -88v-288h-60v288q0 36 -4 67.5t-16 55.5t-34 37.5t-58 13.5q-57 0 -89.5 -21t-49 -49.5t-21 -58t-4.5 -45.5v-288h-60v288q0 36 -4 68+t-16 55.5t-34 37t-58 13.5q-57 0 -89.5 -21t-49 -49.5t-21 -58t-4.5 -45.5v-288h-60v502h60z" />+    <glyph glyph-name="n" unicode="n" horiz-adv-x="551" +d="M294 462q-73 0 -116 -46t-43 -127v-289h-60v502h60v-76h2q52 91 157 91q53 0 87.5 -18.5t54.5 -50t27.5 -72.5t7.5 -87v-289h-60v289q0 33 -3.5 64t-15.5 55t-35 39t-63 15z" />+    <glyph glyph-name="o" unicode="o" horiz-adv-x="560" +d="M111 251q0 -38 10.5 -75.5t31.5 -67.5t52.5 -49t74.5 -19q42 0 74 18.5t53 48.5t31.5 67.5t10.5 75.5q0 37 -10.5 75t-31.5 68.5t-53 49.5t-74 19q-43 0 -75 -18.5t-53 -48.5t-31 -68t-10 -76zM45 251q0 52 15.5 100.5t45.5 85t73.5 58.5t99.5 22q57 0 101 -22t74 -58.5+t45.5 -85t15.5 -101.5t-16 -101t-46 -84.5t-74 -58t-100 -21.5t-99.5 22t-73.5 58.5t-45.5 84.5t-15.5 101z" />+    <glyph glyph-name="p" unicode="p" horiz-adv-x="550" +d="M287 462q-55 0 -92 -31.5t-55.5 -78t-18.5 -101.5t18.5 -101.5t55.5 -78t92 -31.5q38 0 67 18.5t48.5 48.5t29 68t9.5 78q0 39 -9.5 76.5t-29 67t-48.5 47.5t-67 18zM125 78v-270h-60v694h60v-76h2q52 91 160 91q53 0 94 -22t68.5 -59t41.5 -84t14 -97t-14.5 -98.5+t-42 -87t-68.5 -61.5t-93 -23q-54 0 -91 22.5t-69 70.5h-2z" />+    <glyph glyph-name="q" unicode="q" horiz-adv-x="551" +d="M255 40q42 0 74.5 18t54 48t33 68t11.5 78t-11.5 77.5t-33 67t-54 47.5t-74.5 18q-37 0 -64 -18t-45 -47t-27.5 -67t-9.5 -77q-1 -40 8.5 -78t28.5 -68t46.5 -48.5t62.5 -18.5zM486 502v-693h-60v269h-2q-65 -93 -169 -93q-51 0 -90 23t-65.5 61t-40.5 86.5t-14 99.5+q0 49 13.5 96t40 84t66 59.5t90.5 22.5q52 0 97.5 -23.5t71.5 -65.5h2v74h60z" />+    <glyph glyph-name="r" unicode="r" horiz-adv-x="330" +d="M75 0v502h60v-74h2q16 42 51.5 65.5t80.5 23.5h41v-55q-44 0 -76.5 -7t-54.5 -25t-33 -49t-11 -79v-302h-60z" />+    <glyph glyph-name="s" unicode="s" +d="M63 377q0 39 16.5 65.5t42.5 43t59 24t66 7.5q39 0 72.5 -9.5t58 -29.5t38.5 -52.5t14 -78.5h-65q0 35 -8 57.5t-24 35t-39 17.5t-53 5q-19 0 -39 -4t-36.5 -13.5t-27 -25t-10.5 -38.5q0 -31 23.5 -47t59 -26.5t76.5 -19t76.5 -24t59 -42.5t23.5 -73q0 -43 -19 -74+t-49 -51t-67.5 -29.5t-75.5 -9.5q-91 0 -140.5 45.5t-48.5 138.5h65q-1 -73 34.5 -101t104.5 -28q23 0 46.5 5.5t42 17.5t30.5 31t12 46q0 36 -23.5 54.5t-59 29t-76.5 18.5t-76.5 22.5t-59 40t-23.5 72.5z" />+    <glyph glyph-name="t" unicode="t" horiz-adv-x="336" +d="M245 -15q-42 0 -66 10t-36 29t-15 46.5t-3 63.5v313h-100v55h100v133h60v-133h121v-55h-121v-313q0 -17 1.5 -34.5t7.5 -32t18.5 -23.5t33.5 -9q15 0 30 3t30 5v-49q-15 -4 -30 -6.5t-31 -2.5z" />+    <glyph glyph-name="u" unicode="u" horiz-adv-x="551" +d="M257 40q33 0 62 8t50.5 25t34 43t12.5 62v324h60v-502h-60v76h-2q-25 -45 -65.5 -68t-91.5 -23q-44 0 -77 14.5t-55.5 40.5t-33.5 61t-11 77v324h60v-324q0 -27 7 -52t21 -44t36.5 -30.5t52.5 -11.5z" />+    <glyph glyph-name="v" unicode="v" horiz-adv-x="502" +d="M15 502h66l173 -436l167 436h66l-199 -502h-68z" />+    <glyph glyph-name="w" unicode="w" horiz-adv-x="832" +d="M81 502l150 -423h2l152 423h71l148 -419h2l145 419h66l-187 -502h-57l-154 433h-2l-157 -433h-61l-184 502h66z" />+    <glyph glyph-name="x" unicode="x" horiz-adv-x="502" +d="M254 300l151 202h63l-180 -243l196 -259h-79l-161 218l-158 -218h-68l2 2l192 255l-185 245h80z" />+    <glyph glyph-name="y" unicode="y" +d="M10 502h73l169 -420l168 420h65l-277 -694h-66l76 192z" />+    <glyph glyph-name="z" unicode="z" horiz-adv-x="444" +d="M40 0v55l293 392h-293v55h364v-55l-291 -392h291v-55h-364z" />+    <glyph glyph-name="braceleft" unicode="{" horiz-adv-x="290" +d="M112 262q35 -22 48 -58t15 -77t-1 -81.5t0.5 -73t19.5 -52t56 -16.5v-50h-50q-44 0 -62 26.5t-22.5 67t-2 88t-0.5 90t-18 72.5t-55 36v55q29 4 44.5 22t22 45.5t6.5 62t-0.5 69.5t1 68t9.5 59t26 41.5t51 15.5h50v-50q-39 2 -54.5 -15.5t-19 -47.5t-0.5 -69t1 -80+t-15.5 -79.5t-49.5 -68.5z" />+    <glyph glyph-name="bar" unicode="|" horiz-adv-x="220" +d="M80 -230v1000h60v-1000h-60z" />+    <glyph glyph-name="braceright" unicode="}" horiz-adv-x="280" +d="M168 264q-35 25 -48 62t-15.5 77.5t0.5 80.5t-0.5 71.5t-19.5 50t-55 16.5v50h50q32 0 49.5 -15.5t25.5 -41t8.5 -58.5t0 -67.5t0 -68.5t7.5 -61.5t23 -46t46 -22.5v-55q-30 -4 -45.5 -22.5t-22 -46.5t-6.5 -61.5t0.5 -68.5t-0.5 -68t-9 -58.5t-26 -41t-51 -15.5h-50v50+q39 -3 55 13t19 44t0 65t-1 78t15.5 82.5t49.5 77.5z" />+    <glyph glyph-name="asciitilde" unicode="~" horiz-adv-x="660" +d="M221 319q28 0 57.5 -11.5t58.5 -25t55.5 -24.5t48.5 -11q18 0 33 8t27.5 21t22 28.5t16.5 29.5l40 -34q-11 -20 -25 -39.5t-31 -35t-38 -25t-46 -9.5q-23 0 -54.5 11.5t-62.5 25t-57.5 25t-38.5 11.5q-21 0 -38 -8.5t-31 -22t-25 -30.5t-20 -34l-33 47q12 18 26.5 36.5+t31.5 33.5t38 24t45 9z" />+    <glyph glyph-name="emdash" unicode="&#x2014;" horiz-adv-x="1020" +d="M958 230h-916v32h916v-32z" />+    <glyph glyph-name="trademark" unicode="&#x2122;" horiz-adv-x="940" +d="M643 411h2l118 311h99v-421h-55v377h-2l-145 -377h-34l-145 377h-2v-377h-55v421h99zM349 682h-132v-381h-55v381h-133v40h320v-40z" />+    <glyph glyph-name="copyright" unicode="&#xa9;" horiz-adv-x="825" +d="M401 -15q-79 0 -147.5 29.5t-119.5 80.5t-80.5 119.5t-29.5 147.5q0 78 29.5 146.5t80.5 119.5t120 80t147 29t146.5 -29.5t119 -80t80 -119t29.5 -146.5t-29 -146.5t-80 -120t-119.5 -81t-146.5 -29.5zM84 362q0 -69 23.5 -127.5t65.5 -100.5t100 -65.5t128 -23.5+q69 0 127 23.5t100 66t65 100.5t23 127t-23.5 126.5t-65.5 99.5t-99.5 65.5t-126.5 23.5t-127 -23t-100.5 -65t-66 -100t-23.5 -127zM591 294q-3 -34 -19 -61t-40 -46t-54.5 -29t-62.5 -10q-48 0 -86 16.5t-64.5 45.5t-40.5 68.5t-14 86.5t14 86.5t40 68t64.5 44.5t86.5 16+q33 0 63 -9.5t53.5 -27.5t39 -44.5t20.5 -60.5h-55q-5 21 -16.5 38t-28 29t-36 18.5t-40.5 6.5q-36 0 -63.5 -13t-45.5 -35.5t-27 -52t-9 -63.5q0 -33 9.5 -63.5t27.5 -53.5t45 -37t63 -14q21 0 41.5 7t37 19.5t28 30t14.5 39.5h55z" />+    <glyph glyph-name="registered" unicode="&#xae;" horiz-adv-x="825" +d="M401 -15q-78 0 -147 29.5t-120 80.5t-80.5 120t-29.5 147t29.5 146.5t81 119t120 80t146.5 29.5t146 -29.5t119 -80.5t80.5 -119t29.5 -146t-29.5 -146.5t-80 -120t-119 -81t-146.5 -29.5zM401 45q69 0 127 24t99.5 66t65 100t23.5 127q0 68 -23.5 126t-65.5 100+t-100 65.5t-126 23.5q-69 0 -127 -23.5t-100 -65t-66 -99.5t-24 -127t23.5 -127.5t65.5 -100.5t100.5 -65.5t127.5 -23.5zM315 340v-191h-55v430h185q31 0 58.5 -5t48 -18.5t32 -36.5t11.5 -59q0 -31 -10 -53t-28 -36.5t-42.5 -21.5t-52.5 -9l128 -191h-62l-121 191h-92z+M315 390h114q20 0 39 1.5t34 8.5t24 21.5t9 39.5q0 23 -9 36.5t-23.5 20.5t-33 9t-36.5 2h-118v-139z" />+    <glyph glyph-name="degree" unicode="&#xb0;" horiz-adv-x="391" +d="M200 681q29 0 55 -11t45.5 -30.5t30.5 -45.5t11 -55t-11 -55t-30.5 -45.5t-45.5 -31t-55 -11.5q-30 0 -55.5 11t-45 30.5t-30.5 45.5t-11 56t11 55.5t30.5 45t45 30.5t55.5 11zM100 539q0 -43 28.5 -71.5t71.5 -28.5q44 0 72 28t28 72t-29 71.5t-72 27.5t-71 -28t-28 -71+z" />+    <glyph glyph-name="Aacute" unicode="&#xc1;" horiz-adv-x="667" +d="M453 927l-127 -143h-44l91 143h80zM9 0l286 722h76l288 -722h-71l-77 195h-359l-76 -195h-67zM488 255l-156 407l-159 -407h315z" />+    <glyph glyph-name="Acircumflex" unicode="&#xc2;" horiz-adv-x="667" +d="M298 927h73l99 -145h-47l-89 106l-90 -106h-46zM9 0l286 722h76l288 -722h-71l-77 195h-359l-76 -195h-67zM488 255l-156 407l-159 -407h315z" />+    <glyph glyph-name="Adieresis" unicode="&#xc4;" horiz-adv-x="667" +d="M210 839v88h74v-88h-74zM384 839v88h74v-88h-74zM9 0l286 722h76l288 -722h-71l-77 195h-359l-76 -195h-67zM488 255l-156 407l-159 -407h315z" />+    <glyph glyph-name="Aring" unicode="&#xc5;" horiz-adv-x="667" +d="M173 255h315l-156 407zM76 0h-67l286 722h76l288 -722h-71l-77 195h-359zM389 869q0 21 -17 38t-38 17q-22 0 -38.5 -16.5t-16.5 -38.5q0 -21 17 -38t38 -17q20 0 37.5 17.5t17.5 37.5zM246 869q0 18 7 34t19 28t28 19t34 7t34 -7t28 -19t19 -28t7 -34t-7 -34t-19 -28+t-28 -19t-34 -7t-34 7t-28 19t-19 28t-7 34z" />+    <glyph glyph-name="Ccedilla" unicode="&#xc7;" horiz-adv-x="667" +d="M255 -133q25 -11 48.5 -18t40.5 -7q20 0 37 8.5t17 34.5q0 19 -15.5 29t-32.5 7h-21l11 67q-75 6 -128 39.5t-86.5 85t-49 116t-15.5 132.5q0 73 18 141t56 120.5t96.5 83.5t140.5 31q44 0 85.5 -10.5t74.5 -33t54.5 -57.5t25.5 -83h-70q-5 33 -20.5 56.5t-38.5 38.5+t-52 22t-59 7q-68 0 -114 -27.5t-74 -72.5t-40.5 -101.5t-12.5 -114.5t12.5 -114.5t40.5 -101.5t74 -72.5t114 -27.5q31 0 60.5 8t53.5 24.5t41 41t23 56.5h70q-8 -45 -31.5 -80.5t-57 -59.5t-75 -37t-84.5 -13l-9 1l-5 -39q19 2 36 1t30.5 -8t21.5 -21t8 -36+q0 -18 -8 -30.5t-21.5 -20.5t-30 -11.5t-33.5 -3.5q-30 1 -57 7t-56 15z" />+    <glyph glyph-name="Egrave" unicode="&#xc8;" horiz-adv-x="611" +d="M267 927l91 -143h-44l-127 143h80zM102 0v722h429v-60h-364v-259h350v-60h-350v-283h379v-60h-444z" />+    <glyph glyph-name="Eacute" unicode="&#xc9;" horiz-adv-x="611" +d="M425 927l-127 -143h-44l91 143h80zM102 0v722h429v-60h-364v-259h350v-60h-350v-283h379v-60h-444z" />+    <glyph glyph-name="Ecircumflex" unicode="&#xca;" horiz-adv-x="611" +d="M270 927h73l99 -145h-47l-89 106l-90 -106h-46zM102 0v722h429v-60h-364v-259h350v-60h-350v-283h379v-60h-444z" />+    <glyph glyph-name="Edieresis" unicode="&#xcb;" horiz-adv-x="611" +d="M182 839v88h74v-88h-74zM356 839v88h74v-88h-74zM102 0v722h429v-60h-364v-259h350v-60h-350v-283h379v-60h-444z" />+    <glyph glyph-name="Igrave" unicode="&#xcc;" horiz-adv-x="278" +d="M100 927l91 -143h-44l-127 143h80zM107 0v725h65v-725h-65z" />+    <glyph glyph-name="Iacute" unicode="&#xcd;" horiz-adv-x="278" +d="M258 927l-127 -143h-44l91 143h80zM107 0v725h65v-725h-65z" />+    <glyph glyph-name="Icircumflex" unicode="&#xce;" horiz-adv-x="278" +d="M103 927h73l99 -145h-47l-89 106l-90 -106h-46zM107 0v725h65v-725h-65z" />+    <glyph glyph-name="Idieresis" unicode="&#xcf;" horiz-adv-x="278" +d="M15 839v88h74v-88h-74zM189 839v88h74v-88h-74zM107 0v725h65v-725h-65z" />+    <glyph glyph-name="Ntilde" unicode="&#xd1;" horiz-adv-x="719" +d="M90 0v722h74l398 -635h2v635h65v-722h-82l-390 624h-2v-624h-65zM497 915q-8 -34 -30.5 -59.5t-60.5 -25.5q-13 0 -25 3.5l-24 7t-24.5 7t-25.5 3.5q-16 0 -29 -6t-18 -23h-38q8 35 30 58t60 23q26 0 49.5 -10.5t47.5 -10.5q36 0 50 33h38z" />+    <glyph glyph-name="Ograve" unicode="&#xd2;" horiz-adv-x="778" +d="M350 927l91 -143h-44l-127 143h80zM711 361q0 -84 -21 -153.5t-62 -119t-101 -76.5t-138 -27t-138 27t-101 76.5t-62 119t-21 153.5t21 153.5t62 119t101 76.5t138 27t138 -27t101 -76.5t62 -119t21 -153.5zM137 361q0 -59 14 -116t44.5 -101.5t78 -71.5t115.5 -27+q67 0 115 27t78.5 71.5t44.5 101.5t14 116t-14 116t-44.5 101.5t-78.5 71.5t-115 27q-68 0 -115.5 -27t-78 -71.5t-44.5 -101.5t-14 -116z" />+    <glyph glyph-name="Oacute" unicode="&#xd3;" horiz-adv-x="778" +d="M387 677q-68 0 -116 -27.5t-78 -72.5t-44 -102t-14 -117q0 -59 14.5 -115t45.5 -100t78.5 -71t113.5 -27q68 0 116 28t78 73t44 102.5t14 117.5q0 58 -14.5 114t-45.5 100t-78.5 70.5t-113.5 26.5zM387 737q83 0 144 -30t100.5 -81.5t58.5 -120t19 -144.5t-19 -144.5+t-58.5 -120t-100.5 -81.5t-144 -30q-84 0 -144.5 30t-100 81.5t-58.5 119.5t-19 145q0 76 19 144.5t58.5 120t100 81.5t144.5 30zM508 927l-127 -143h-44l91 143h80z" />+    <glyph glyph-name="Ocircumflex" unicode="&#xd4;" horiz-adv-x="778" +d="M387 677q-68 0 -116 -27.5t-78 -72.5t-44 -102t-14 -117q0 -59 14.5 -115t45.5 -100t78.5 -71t113.5 -27q68 0 116 28t78 73t44 102.5t14 117.5q0 58 -14.5 114t-45.5 100t-78.5 70.5t-113.5 26.5zM387 737q83 0 144 -30t100.5 -81.5t58.5 -120t19 -144.5t-19 -144.5+t-58.5 -120t-100.5 -81.5t-144 -30q-84 0 -144.5 30t-100 81.5t-58.5 119.5t-19 145q0 76 19 144.5t58.5 120t100 81.5t144.5 30zM353 927h73l99 -145h-47l-89 106l-90 -106h-46z" />+    <glyph glyph-name="Odieresis" unicode="&#xd6;" horiz-adv-x="778" +d="M387 677q-68 0 -116 -27.5t-78 -72.5t-44 -102t-14 -117q0 -59 14.5 -115t45.5 -100t78.5 -71t113.5 -27q68 0 116 28t78 73t44 102.5t14 117.5q0 58 -14.5 114t-45.5 100t-78.5 70.5t-113.5 26.5zM387 737q83 0 144 -30t100.5 -81.5t58.5 -120t19 -144.5t-19 -144.5+t-58.5 -120t-100.5 -81.5t-144 -30q-84 0 -144.5 30t-100 81.5t-58.5 119.5t-19 145q0 76 19 144.5t58.5 120t100 81.5t144.5 30zM265 839v88h74v-88h-74zM439 839v88h74v-88h-74z" />+    <glyph glyph-name="multiply" unicode="&#xd7;" horiz-adv-x="631" +d="M591 9l-23 -23l-237 236l-239 -236l-23 23l238 235l-238 237l23 23l239 -236l237 236l23 -23l-237 -237z" />+    <glyph glyph-name="Oslash" unicode="&#xd8;" horiz-adv-x="778" +d="M209 127q33 -42 80 -62t100 -20q67 0 115 27t78.5 71.5t44.5 101.5t14 116q0 52 -11 103.5t-37 96.5zM83 -15l-29 27l84 94q-41 54 -56 121t-15 134q0 76 19 144.5t58.5 120t100.5 81.5t144 30q64 0 123.5 -22t104.5 -70l82 92l27 -25l-85 -97q39 -55 54.5 -121.5+t15.5 -132.5q0 -77 -19 -145t-58.5 -119.5t-100.5 -81.5t-144 -30q-64 0 -122.5 21.5t-103.5 69.5zM571 593q-33 42 -80.5 63t-101.5 21q-67 0 -115 -27t-78.5 -71.5t-44.5 -101.5t-14 -116q0 -52 10.5 -104t38.5 -97z" />+    <glyph glyph-name="Ugrave" unicode="&#xd9;" horiz-adv-x="722" +d="M322 927l91 -143h-44l-127 143h80zM162 722v-467q0 -46 13.5 -84.5t39 -66.5t62.5 -43.5t84 -15.5t84 15.5t62.5 43.5t39 66.5t13.5 84.5v467h65v-468q0 -61 -18 -110.5t-52 -85t-83 -54.5t-111 -19t-111 19t-83 54.5t-52 85t-18 110.5v468h65z" />+    <glyph glyph-name="Uacute" unicode="&#xda;" horiz-adv-x="722" +d="M100 722h65v-467q0 -45 13.5 -83.5t39 -66.5t62.5 -44t84 -16t84 16t62.5 44t39 66.5t13.5 83.5v467h65v-468q0 -61 -18 -110.5t-52 -85t-83 -54.5t-111 -19t-111 19t-83 54.5t-52 85t-18 110.5v468zM480 927l-127 -143h-44l91 143h80z" />+    <glyph glyph-name="Ucircumflex" unicode="&#xdb;" horiz-adv-x="722" +d="M325 927h73l99 -145h-47l-89 106l-90 -106h-46zM162 722v-467q0 -46 13.5 -84.5t39 -66.5t62.5 -43.5t84 -15.5t84 15.5t62.5 43.5t39 66.5t13.5 84.5v467h65v-468q0 -61 -18 -110.5t-52 -85t-83 -54.5t-111 -19t-111 19t-83 54.5t-52 85t-18 110.5v468h65z" />+    <glyph glyph-name="Udieresis" unicode="&#xdc;" horiz-adv-x="722" +d="M100 722h65v-467q0 -45 13.5 -83.5t39 -66.5t62.5 -44t84 -16t84 16t62.5 44t39 66.5t13.5 83.5v467h65v-468q0 -61 -18 -110.5t-52 -85t-83 -54.5t-111 -19t-111 19t-83 54.5t-52 85t-18 110.5v468zM237 839v88h74v-88h-74zM411 839v88h74v-88h-74z" />+    <glyph glyph-name="agrave" unicode="&#xe0;" +d="M101 140q0 -49 29.5 -74.5t72.5 -25.5q27 0 55.5 8t52 23t38.5 36.5t15 48.5v81h-44h-57t-73 -8t-62.5 -28.5t-26.5 -60.5zM36 140q0 42 16 69.5t42.5 44.5t60.5 25t70.5 11t72.5 2.5t66 -0.5q0 37 -2.5 68.5t-15 54t-38.5 35t-72 12.5q-57 0 -90.5 -32.5t-33.5 -82.5+h-64q0 39 15.5 70.5t41.5 53.5t60 34t72 12q96 0 141.5 -44.5t45.5 -121.5v-351h-59v74h-2q-10 -23 -27.5 -39.5t-39 -27.5t-46 -16.5t-47.5 -5.5q-35 0 -65.5 10.5t-53 30.5t-35.5 49t-13 65zM211 707l91 -143h-44l-127 143h80z" />+    <glyph glyph-name="aacute" unicode="&#xe1;" +d="M101 140q0 -49 29.5 -74.5t72.5 -25.5q27 0 55.5 8t52 23t38.5 36.5t15 48.5v81h-44h-57t-73 -8t-62.5 -28.5t-26.5 -60.5zM36 140q0 42 16 69.5t42.5 44.5t60.5 25t70.5 11t72.5 2.5t66 -0.5q0 37 -2.5 68.5t-15 54t-38.5 35t-72 12.5q-57 0 -90.5 -32.5t-33.5 -82.5+h-64q0 39 15.5 70.5t41.5 53.5t60 34t72 12q96 0 141.5 -44.5t45.5 -121.5v-351h-59v74h-2q-10 -23 -27.5 -39.5t-39 -27.5t-46 -16.5t-47.5 -5.5q-35 0 -65.5 10.5t-53 30.5t-35.5 49t-13 65zM369 707l-127 -143h-44l91 143h80z" />+    <glyph glyph-name="acircumflex" unicode="&#xe2;" +d="M101 140q0 -49 29.5 -74.5t72.5 -25.5q27 0 55.5 8t52 23t38.5 36.5t15 48.5v81h-44h-57t-73 -8t-62.5 -28.5t-26.5 -60.5zM36 140q0 42 16 69.5t42.5 44.5t60.5 25t70.5 11t72.5 2.5t66 -0.5q0 37 -2.5 68.5t-15 54t-38.5 35t-72 12.5q-57 0 -90.5 -32.5t-33.5 -82.5+h-64q0 39 15.5 70.5t41.5 53.5t60 34t72 12q96 0 141.5 -44.5t45.5 -121.5v-351h-59v74h-2q-10 -23 -27.5 -39.5t-39 -27.5t-46 -16.5t-47.5 -5.5q-35 0 -65.5 10.5t-53 30.5t-35.5 49t-13 65zM214 707h73l99 -145h-47l-89 106l-90 -106h-46z" />+    <glyph glyph-name="atilde" unicode="&#xe3;" +d="M101 140q0 -49 29.5 -74.5t72.5 -25.5q27 0 55.5 8t52 23t38.5 36.5t15 48.5v81h-44h-57t-73 -8t-62.5 -28.5t-26.5 -60.5zM36 140q0 42 16 69.5t42.5 44.5t60.5 25t70.5 11t72.5 2.5t66 -0.5q0 37 -2.5 68.5t-15 54t-38.5 35t-72 12.5q-57 0 -90.5 -32.5t-33.5 -82.5+h-64q0 39 15.5 70.5t41.5 53.5t60 34t72 12q96 0 141.5 -44.5t45.5 -121.5v-351h-59v74h-2q-10 -23 -27.5 -39.5t-39 -27.5t-46 -16.5t-47.5 -5.5q-35 0 -65.5 10.5t-53 30.5t-35.5 49t-13 65zM126 619v88h74v-88h-74zM300 619v88h74v-88h-74z" />+    <glyph glyph-name="adieresis" unicode="&#xe4;" +d="M101 140q0 -49 29.5 -74.5t72.5 -25.5q27 0 55.5 8t52 23t38.5 36.5t15 48.5v81h-44h-57t-73 -8t-62.5 -28.5t-26.5 -60.5zM36 140q0 42 16 69.5t42.5 44.5t60.5 25t70.5 11t72.5 2.5t66 -0.5q0 37 -2.5 68.5t-15 54t-38.5 35t-72 12.5q-57 0 -90.5 -32.5t-33.5 -82.5+h-64q0 39 15.5 70.5t41.5 53.5t60 34t72 12q96 0 141.5 -44.5t45.5 -121.5v-351h-59v74h-2q-10 -23 -27.5 -39.5t-39 -27.5t-46 -16.5t-47.5 -5.5q-35 0 -65.5 10.5t-53 30.5t-35.5 49t-13 65zM388 695q-8 -34 -30.5 -59.5t-60.5 -25.5q-11 0 -22 3t-23 8q-11 4 -24.5 7+t-29.5 3q-15 0 -29 -7t-18 -22h-38q9 41 36.5 64t71.5 16q7 -1 18 -4t22 -7l22 -6t17 -3q17 0 30.5 8.5t19.5 24.5h38z" />+    <glyph glyph-name="aring" unicode="&#xe5;" +d="M101 140q0 -49 29.5 -74.5t72.5 -25.5q27 0 55.5 8t52 23t38.5 36.5t15 48.5v81h-44h-57t-73 -8t-62.5 -28.5t-26.5 -60.5zM36 140q0 42 16 69.5t42.5 44.5t60.5 25t70.5 11t72.5 2.5t66 -0.5q0 37 -2.5 68.5t-15 54t-38.5 35t-72 12.5q-57 0 -90.5 -32.5t-33.5 -82.5+h-64q0 39 15.5 70.5t41.5 53.5t60 34t72 12q96 0 141.5 -44.5t45.5 -121.5v-351h-59v74h-2q-10 -23 -27.5 -39.5t-39 -27.5t-46 -16.5t-47.5 -5.5q-35 0 -65.5 10.5t-53 30.5t-35.5 49t-13 65zM305 649q0 21 -17 38t-38 17t-38 -16.5t-17 -38.5q0 -20 17 -37.5t38 -17.5+q20 0 37.5 17.5t17.5 37.5zM162 649q0 18 7 34t19 28t28 19t34 7t34 -7t28 -19t19 -28t7 -34t-7 -34t-19 -28t-28 -19t-34 -7t-34 7t-28 19t-19 28t-7 34z" />+    <glyph glyph-name="ccedilla" unicode="&#xe7;" +d="M394 349q-1 31 -14 57q-11 21 -35.5 39t-71.5 18t-78.5 -21t-50.5 -52t-27 -66t-8 -63t6 -66t23 -72.5t48 -58.5t81 -24t76.5 18t37.5 41q13 26 14 59q6 -1 16 -1h49q0 -30 -11.5 -60.5t-35 -55t-59 -40.5t-83.5 -16v-36q26 2 47 -3q17 -5 32 -18.5t15 -42.5+q0 -22 -9 -35.5t-24 -21t-34 -9.5t-38 -1q-47 3 -105 20q2 5 4 9q4 9 5 18q16 -8 40 -13t46.5 -5t38.5 8t16 27t-10 26.5t-22 9.5q-14 2 -32 -3v72q-44 5 -76 22t-54 41t-35 52.5t-20.5 57t-9.5 55t-2 45.5q0 16 4.5 41t14.5 53.5t26.5 57.5t41 52.5t57 38t75.5 14.5+q35 0 62.5 -7t47.5 -19t34.5 -27t24.5 -31q23 -37 29 -83l-67 -1v0z" />+    <glyph glyph-name="egrave" unicode="&#xe8;" horiz-adv-x="560" +d="M116 237q1 -41 9.5 -77t28 -62.5t51 -42t76.5 -15.5q27 0 52 9t45.5 25t35.5 38t21 48h63q-22 -84 -75.5 -129.5t-141.5 -45.5q-55 0 -98.5 21t-73.5 56.5t-45.5 82.5t-15.5 99q0 49 15 98t44 88t71.5 63t96.5 24q64 0 107.5 -22.5t70.5 -61t39 -89t12 -107.5h-388z+M439 292q-3 36 -14 67.5t-31 54t-49.5 35.5t-68.5 13q-36 0 -64.5 -14t-48 -37.5t-31 -54.5t-14.5 -64h321zM240 707l91 -143h-44l-127 143h80z" />+    <glyph glyph-name="eacute" unicode="&#xe9;" horiz-adv-x="560" +d="M116 237q1 -41 9.5 -77t28 -62.5t51 -42t76.5 -15.5q27 0 52 9t45.5 25t35.5 38t21 48h63q-22 -84 -75.5 -129.5t-141.5 -45.5q-55 0 -98.5 21t-73.5 56.5t-45.5 82.5t-15.5 99q0 49 15 98t44 88t71.5 63t96.5 24q64 0 107.5 -22.5t70.5 -61t39 -89t12 -107.5h-388z+M439 292q-3 36 -14 67.5t-31 54t-49.5 35.5t-68.5 13q-36 0 -64.5 -14t-48 -37.5t-31 -54.5t-14.5 -64h321zM398 707l-127 -143h-44l91 143h80z" />+    <glyph glyph-name="ecircumflex" unicode="&#xea;" horiz-adv-x="560" +d="M116 237q1 -41 9.5 -77t28 -62.5t51 -42t76.5 -15.5q27 0 52 9t45.5 25t35.5 38t21 48h63q-22 -84 -75.5 -129.5t-141.5 -45.5q-55 0 -98.5 21t-73.5 56.5t-45.5 82.5t-15.5 99q0 49 15 98t44 88t71.5 63t96.5 24q64 0 107.5 -22.5t70.5 -61t39 -89t12 -107.5h-388z+M439 292q-3 36 -14 67.5t-31 54t-49.5 35.5t-68.5 13q-36 0 -64.5 -14t-48 -37.5t-31 -54.5t-14.5 -64h321zM243 707h73l99 -145h-47l-89 106l-90 -106h-46z" />+    <glyph glyph-name="edieresis" unicode="&#xeb;" horiz-adv-x="560" +d="M116 237q1 -41 9.5 -77t28 -62.5t51 -42t76.5 -15.5q27 0 52 9t45.5 25t35.5 38t21 48h63q-22 -84 -75.5 -129.5t-141.5 -45.5q-55 0 -98.5 21t-73.5 56.5t-45.5 82.5t-15.5 99q0 49 15 98t44 88t71.5 63t96.5 24q64 0 107.5 -22.5t70.5 -61t39 -89t12 -107.5h-388z+M439 292q-3 36 -14 67.5t-31 54t-49.5 35.5t-68.5 13q-36 0 -64.5 -14t-48 -37.5t-31 -54.5t-14.5 -64h321zM155 619v88h74v-88h-74zM329 619v88h74v-88h-74z" />+    <glyph glyph-name="igrave" unicode="&#xec;" horiz-adv-x="222" +d="M72 707l91 -143h-44l-127 143h80zM81 0v502h60v-502h-60z" />+    <glyph glyph-name="iacute" unicode="&#xed;" horiz-adv-x="222" +d="M230 707l-127 -143h-44l91 143h80zM81 0v502h60v-502h-60z" />+    <glyph glyph-name="icircumflex" unicode="&#xee;" horiz-adv-x="222" +d="M75 707h73l99 -145h-47l-89 106l-90 -106h-46zM81 0v502h60v-502h-60z" />+    <glyph glyph-name="idieresis" unicode="&#xef;" horiz-adv-x="222" +d="M-13 619v88h74v-88h-74zM161 619v88h74v-88h-74zM81 0v502h60v-502h-60z" />+    <glyph glyph-name="ntilde" unicode="&#xf1;" horiz-adv-x="551" +d="M411 695q-8 -34 -30.5 -59.5t-60.5 -25.5q-13 0 -25 3.5l-24 7t-24.5 7t-25.5 3.5q-16 0 -29 -6t-18 -23h-38q8 35 30 58t60 23q26 0 49.5 -10.5t47.5 -10.5q36 0 50 33h38zM294 462q-36 0 -65.5 -14t-50.5 -37.5t-32 -55t-11 -66.5v-289h-60v502h60v-76h2q52 91 157 91+q53 0 87.5 -18.5t54.5 -50t27.5 -72.5t7.5 -87v-289h-60v289q0 33 -3.5 64t-15.5 55t-35 39t-63 15z" />+    <glyph glyph-name="ograve" unicode="&#xf2;" horiz-adv-x="556" +d="M239 707l91 -143h-44l-127 143h80zM278 517q60 0 104 -23t73 -60.5t43 -85.5t14 -97q0 -50 -14 -97.5t-43 -85t-73 -60.5t-104 -23t-104 23t-73 60.5t-43 85t-14 97.5q0 49 14 97t43 85.5t73 60.5t104 23zM447 251q0 35 -9.5 72.5t-29.5 68t-52.5 50.5t-77.5 20+t-77.5 -20t-52.5 -50.5t-29.5 -68t-9.5 -72.5t9.5 -72.5t29.5 -68t52.5 -50.5t77.5 -20t77.5 20t52.5 50.5t29.5 68t9.5 72.5z" />+    <glyph glyph-name="oacute" unicode="&#xf3;" horiz-adv-x="556" +d="M397 707l-127 -143h-44l91 143h80zM278 517q60 0 104 -23t73 -60.5t43 -85.5t14 -97q0 -50 -14 -97.5t-43 -85t-73 -60.5t-104 -23t-104 23t-73 60.5t-43 85t-14 97.5q0 49 14 97t43 85.5t73 60.5t104 23zM447 251q0 35 -9.5 72.5t-29.5 68t-52.5 50.5t-77.5 20+t-77.5 -20t-52.5 -50.5t-29.5 -68t-9.5 -72.5t9.5 -72.5t29.5 -68t52.5 -50.5t77.5 -20t77.5 20t52.5 50.5t29.5 68t9.5 72.5z" />+    <glyph glyph-name="ocircumflex" unicode="&#xf4;" horiz-adv-x="556" +d="M242 707h73l99 -145h-47l-89 106l-90 -106h-46zM278 517q60 0 104 -23t73 -60.5t43 -85.5t14 -97q0 -50 -14 -97.5t-43 -85t-73 -60.5t-104 -23t-104 23t-73 60.5t-43 85t-14 97.5q0 49 14 97t43 85.5t73 60.5t104 23zM447 251q0 35 -9.5 72.5t-29.5 68t-52.5 50.5+t-77.5 20t-77.5 -20t-52.5 -50.5t-29.5 -68t-9.5 -72.5t9.5 -72.5t29.5 -68t52.5 -50.5t77.5 -20t77.5 20t52.5 50.5t29.5 68t9.5 72.5z" />+    <glyph glyph-name="otilde" unicode="&#xf5;" horiz-adv-x="556" +d="M416 695q-8 -34 -30.5 -59.5t-60.5 -25.5q-11 0 -22 3t-23 8q-11 4 -24.5 7t-29.5 3q-15 0 -29 -7t-18 -22h-38q9 41 36.5 64t71.5 16q7 -1 18 -4t22 -7l22 -6t17 -3q17 0 30.5 8.5t19.5 24.5h38zM278 517q60 0 104 -23t73 -60.5t43 -85.5t14 -97q0 -50 -14 -97.5+t-43 -85t-73 -60.5t-104 -23t-104 23t-73 60.5t-43 85t-14 97.5q0 49 14 97t43 85.5t73 60.5t104 23zM447 251q0 35 -9.5 72.5t-29.5 68t-52.5 50.5t-77.5 20t-77.5 -20t-52.5 -50.5t-29.5 -68t-9.5 -72.5t9.5 -72.5t29.5 -68t52.5 -50.5t77.5 -20t77.5 20t52.5 50.5+t29.5 68t9.5 72.5z" />+    <glyph glyph-name="odieresis" unicode="&#xf6;" horiz-adv-x="556" +d="M154 619v88h74v-88h-74zM328 619v88h74v-88h-74zM278 517q60 0 104 -23t73 -60.5t43 -85.5t14 -97q0 -50 -14 -97.5t-43 -85t-73 -60.5t-104 -23t-104 23t-73 60.5t-43 85t-14 97.5q0 49 14 97t43 85.5t73 60.5t104 23zM447 251q0 35 -9.5 72.5t-29.5 68t-52.5 50.5+t-77.5 20t-77.5 -20t-52.5 -50.5t-29.5 -68t-9.5 -72.5t9.5 -72.5t29.5 -68t52.5 -50.5t77.5 -20t77.5 20t52.5 50.5t29.5 68t9.5 72.5z" />+    <glyph glyph-name="ugrave" unicode="&#xf9;" horiz-adv-x="556" +d="M257 40q33 0 62 8t50.5 25t34 43t12.5 62v324h60v-502h-60v76h-2q-25 -45 -65.5 -68t-91.5 -23q-44 0 -77 14.5t-55.5 40.5t-33.5 61t-11 77v324h60v-324q0 -27 7 -52t21 -44t36.5 -30.5t52.5 -11.5zM239 707l91 -143h-44l-127 143h80z" />+    <glyph glyph-name="uacute" unicode="&#xfa;" horiz-adv-x="556" +d="M257 40q33 0 62 8t50.5 25t34 43t12.5 62v324h60v-502h-60v76h-2q-25 -45 -65.5 -68t-91.5 -23q-44 0 -77 14.5t-55.5 40.5t-33.5 61t-11 77v324h60v-324q0 -27 7 -52t21 -44t36.5 -30.5t52.5 -11.5zM397 707l-127 -143h-44l91 143h80z" />+    <glyph glyph-name="ucircumflex" unicode="&#xfb;" horiz-adv-x="556" +d="M257 40q33 0 62 8t50.5 25t34 43t12.5 62v324h60v-502h-60v76h-2q-25 -45 -65.5 -68t-91.5 -23q-44 0 -77 14.5t-55.5 40.5t-33.5 61t-11 77v324h60v-324q0 -27 7 -52t21 -44t36.5 -30.5t52.5 -11.5zM242 707h73l99 -145h-47l-89 106l-90 -106h-46z" />+    <glyph glyph-name="udieresis" unicode="&#xfc;" horiz-adv-x="556" +d="M257 40q33 0 62 8t50.5 25t34 43t12.5 62v324h60v-502h-60v76h-2q-25 -45 -65.5 -68t-91.5 -23q-44 0 -77 14.5t-55.5 40.5t-33.5 61t-11 77v324h60v-324q0 -27 7 -52t21 -44t36.5 -30.5t52.5 -11.5zM154 619v88h74v-88h-74zM328 619v88h74v-88h-74z" />+    <glyph glyph-name="dotlessi" unicode="&#x131;" horiz-adv-x="222" +d="M81 0v502h60v-502h-60z" />+    <glyph glyph-name="fraction" unicode="&#x2044;" horiz-adv-x="553" +d="M503 707l-405 -707h-48l407 707h46z" />+    <glyph glyph-name="quotedbl" unicode="&#x22;" horiz-adv-x="281" +d="M58 496v226h52v-226h-52zM168 496v226h52v-226h-52z" />+    <glyph glyph-name="exclam" unicode="!" horiz-adv-x="303" +d="M223 171h-56l-13 551h82zM155 86h80v-86h-80v86z" />+    <hkern u1="B" u2="W" k="55" />+    <hkern u1="V" u2="A" k="65" />+    <hkern u1="a" u2="v" k="35" />+    <hkern u1="e" u2="s" k="20" />+    <hkern u1="n" u2="&#x27;" k="70" />+    <hkern u1="z" u2="e" k="25" />+  </font>+</defs></svg>
puzzle-draw.cabal view
@@ -1,24 +1,30 @@ name:                puzzle-draw-version:             0.1.0.3+version:             0.1.0.4 synopsis:            Creating graphics for pencil puzzles.-description:         puzzle-draw is a library for drawing pencil puzzles-                     using Diagrams. It aims to provide a utility layer-                     on top of Diagrams to help with drawing arbitrary-                     puzzles, as well as supporting several specific-                     puzzle types directly. In addition, it includes-                     functionality for parsing puzzle data from a-                     YAML file format.+description:         puzzle-draw is a library and tool for drawing pencil+                     puzzles using Diagrams. It aims to provide a utility+                     layer on top of Diagrams to help with drawing arbitrary+                     puzzles, and to support several specific puzzles types+                     In addition, it includes functionality for parsing+                     puzzle data from a YAML file format. license:             MIT license-file:        LICENSE author:              Robert Vollmert maintainer:          rfvollmert@gmail.com category:            Graphics build-type:          Simple-Extra-source-files:  README.md, CHANGES.md+extra-source-files:  README.md, CHANGES.md+data-files:          data/fonts/*.svg cabal-version:       >=1.8-Source-repository head++source-repository head   type:     git   location: http://github.com/robx/puzzle-draw.git++flag cairo+  description: Build against Cairo backend+  default:     False+ library   exposed-modules:     Data.Puzzles.Grid                        Data.Puzzles.GridShape@@ -38,33 +44,62 @@                        Diagrams.Puzzles.PuzzleGrids                        Diagrams.Puzzles.PuzzleTypes                        Diagrams.Puzzles.Draw-  build-depends:       base >= 4.2 && < 4.8,-                       diagrams-lib >= 1.1 && < 1.2,-                       parsec >= 3.1 && < 3.2,-                       yaml >= 0.8.4 && < 0.9,-                       aeson >= 0.7 && < 0.8,-                       unordered-containers >= 0.2 && < 0.3,-                       containers >= 0.5 && < 0.6,-                       hashable >= 1.2 && < 1.3,-                       text >= 1.1 && < 1.2,-                       SVGFonts >= 1.4 && < 1.5,-                       vector-space >= 0.8+                       Diagrams.Puzzles.CmdLine+  -- For access to the font files in the data directory.+  other-modules:       Paths_puzzle_draw+  build-depends:       base >= 4.2 && < 5,+                       diagrams-lib >= 1.2,+                       parsec >= 3.1,+                       yaml >= 0.8.4,+                       aeson >= 0.7,+                       unordered-containers >= 0.2,+                       containers >= 0.5,+                       hashable >= 1.2,+                       text >= 1.1,+                       SVGFonts >= 1.4,+                       vector-space >= 0.8,+                       mtl >= 2.1,+                       optparse-applicative >= 0.7,+                       filepath >= 1.3+  if flag(cairo)+    cpp-options: "-DCAIRO"+    build-depends:     diagrams-cairo >= 1.1+  else+    build-depends:     diagrams-svg >= 1.1   hs-source-dirs:      src   ghc-options:         -Wall +executable drawpuzzle+  main-is:          drawpuzzle.hs+  hs-source-dirs:   src/tools+  build-depends:       base >= 4.2,+                       puzzle-draw,+                       diagrams-lib >= 1.2,+                       yaml >= 0.8.4,+                       optparse-applicative >= 0.7,+                       aeson >= 0.7,+                       filepath >= 1.3+  if flag(cairo)+    cpp-options: "-DCAIRO"+    build-depends:     diagrams-cairo >= 1.1+  else+    build-depends:     diagrams-svg >= 1.1+  ghc-options:         -Wall+ test-suite test   type:                exitcode-stdio-1.0   hs-source-dirs:      tests   main-is:             tests.hs-  build-depends:       base >= 4.2 && < 4.8,-                       tasty >= 0.8 && < 0.9,-                       tasty-hunit >= 0.8 && < 0.9,-                       yaml >= 0.8.4 && < 0.9,-                       text >= 1.1 && < 1.2,-                       deepseq >= 1.3 && < 1.4,-                       blaze-svg >= 0.3 && < 0.4,-                       diagrams-lib >= 1.1 && < 1.2,-                       diagrams-svg >= 1.0 && < 1.1,-                       bytestring >= 0.10 && < 0.11,+  build-depends:       base >= 4.2,+                       tasty >= 0.8,+                       tasty-hunit >= 0.8,+                       yaml >= 0.8.4,+                       text >= 1.1,+                       deepseq >= 1.3,+                       containers >= 0.5,+                       blaze-svg >= 0.3,+                       diagrams-lib >= 1.2,+                       diagrams-svg >= 1.1,+                       bytestring >= 0.10,                        puzzle-draw   ghc-options:         -Wall
src/Data/Puzzles/Compose.hs view
@@ -1,4 +1,5 @@ {-# LANGUAGE MultiParamTypeClasses, FlexibleContexts, RankNTypes #-}+{-# LANGUAGE ConstraintKinds #-}  -- | -- Helpers to string together parser and renderer by puzzle type.@@ -22,6 +23,7 @@  import Text.Puzzles.Puzzle import Diagrams.Puzzles.Draw+import Diagrams.Puzzles.Lib import Data.Puzzles.PuzzleTypes  import qualified Text.Puzzles.PuzzleTypes as R@@ -35,7 +37,7 @@  -- | @handle h t@ composes the parser and renderer for the puzzle --   type @t@ with the handler @h@.-handle :: (Backend b R2, Renderable (Path R2) b) =>+handle :: Backend' b =>         PuzzleHandler b a -> PuzzleType -> a handle f LITS                 = f R.lits                D.lits handle f LITSPlus             = f R.litsplus            D.litsplus@@ -59,13 +61,15 @@ handle f Compass              = f R.compass             D.compass handle f BoxOf2Or3            = f R.boxof2or3           D.boxof2or3 handle f AfternoonSkyscrapers = f R.afternoonskyscrapers D.afternoonskyscrapers-handle f CountNumbers         = f R.countnumbers        D.countnumbers+handle f MeanderingNumbers    = f R.meanderingnumbers   D.meanderingnumbers handle f Tapa                 = f R.tapa                D.tapa handle f JapaneseSums         = f R.japanesesums        D.japanesesums handle f Coral                = f R.coral               D.coral handle f MaximalLengths       = f R.maximallengths      D.maximallengths handle f PrimePlace           = f R.primeplace          D.primeplace handle f Labyrinth            = f R.labyrinth           D.labyrinth+handle f Bahnhof              = f R.bahnhof             D.bahnhof+handle f Cave                 = f R.cave                D.cave  -- | Handler that parses a puzzle from a YAML value, and renders. drawPuzzle :: PuzzleHandler b (Value -> Parser (Diagram b R2))@@ -89,7 +93,7 @@                       -> Parser (Diagram b R2, Maybe (Diagram b R2))) drawPuzzleMaybeSol (pp, ps) (dp, ds) (p, s) = do     p' <- pp p-    s' <- traverse ps $ s+    s' <- traverse ps s     let mps = case s' of Nothing  -> Nothing                          Just s'' -> Just (p', s'')     return (dp p', ds <$> mps)@@ -111,7 +115,7 @@     return $ ds (p', s')  -- | Like 'drawSolution'', but renders puzzle and solution in example layout.-drawExample' :: (Backend b R2, Renderable (Path R2) b) =>+drawExample' :: Backend' b =>                 PuzzleHandler b ((Value, Maybe Value) -> Parser (Diagram b R2)) drawExample' (pp, ps) (dp, ds) (p, ms) = do     p' <- pp p
src/Data/Puzzles/Elements.hs view
@@ -6,6 +6,8 @@ type Clue a = Maybe a  data MasyuPearl = MWhite | MBlack+    deriving (Eq, Show)+ type MasyuClue = Clue MasyuPearl  type IntClue = Clue Int@@ -50,14 +52,17 @@ data Shade = Shade Bool Bool     deriving Show -data KropkiDot = None | Black | White+data KropkiDot = KNone | KBlack | KWhite     deriving Show  newtype TapaClue = TapaClue [Int]     deriving Show -data JapVal = JapBlack | JapInt Int-    deriving Show- -- | Diagonal marking for Prime Place: forward diag?, backward diag? newtype PrimeDiag = PrimeDiag (Bool, Bool)++data Black = Black++data Crossing = Crossing++type BahnhofClue = Either Int Crossing
src/Data/Puzzles/Grid.hs view
@@ -6,7 +6,7 @@  import Data.Maybe import qualified Data.Map as Map-import Data.Foldable (Foldable, fold)+import Data.Foldable (Foldable, foldMap) import Data.Traversable (Traversable, traverse) import Control.Applicative ((<$>)) import Data.VectorSpace@@ -21,6 +21,7 @@             , contents :: Map.Map (Cell s) a} -> Grid s a  deriving instance (Show a, Show s, GridShape s) => Show (Grid s a)+deriving instance (Eq s, Eq (Cell s), Eq a) => Eq (Grid s a)  -- | Standard square grid. type SGrid = Grid Square@@ -39,12 +40,12 @@     fmap f (Grid s m) = Grid s (fmap f m)  instance Foldable (Grid s) where-    fold (Grid _ m) = fold m+    foldMap f (Grid _ m) = foldMap f m  instance Traversable (Grid s) where-    traverse f (Grid s m) = Grid s <$> (traverse f m)+    traverse f (Grid s m) = Grid s <$> traverse f m -filterG :: (a -> Bool) -> (Grid s a) -> (Grid s a)+filterG :: (a -> Bool) -> Grid s a -> Grid s a filterG p (Grid s m) = Grid s (Map.filter p m)  -- | Initialize a square grid from a list of lists. The grid@@ -63,7 +64,7 @@ size = GS.size . shape  cells :: GridShape s => Grid s a -> [Cell s]-cells = GS.cells . shape+cells = Map.keys . contents  inBounds :: (GridShape s, Eq (Cell s)) => Grid s a -> Cell s -> Bool inBounds g c = c `elem` cells g@@ -77,17 +78,46 @@ values :: GridShape s => Grid s a -> [(Cell s, a)] values (Grid _ m) = Map.toList m --- | The inner edges of a grid that separate unequal cells.-borders :: Eq a => Grid Square a -> [Edge]-borders g = [ E p V | p <- vborders ] ++ [ E p H | p <- hborders ]+edgesGen :: (a -> a -> Bool) -> (a -> Bool) -> Grid Square a -> [Edge]+edgesGen p n g = [ E pt V | pt <- vedges ] ++ [ E pt H | pt <- hedges ]   where-    borders' f (sx, sy) = [ (x + 1, y) | x <- [0 .. sx - 2]-                                       , y <- [0 .. sy - 1]-                                       , f (x, y) /= f (x + 1, y) ]-    vborders = borders' (g !) (size g)-    hborders = map swap $ borders' ((g !) . swap) (swap . size $ g)+    edges' f (sx, sy) = [ (x + 1, y) | x <- [-1 .. sx - 1]+                                     , y <- [-1 .. sy]+                                     , p' (f (x, y)) (f (x + 1, y)) ]++    vedges = edges' id (size g)+    hedges = map swap $ edges' swap (swap . size $ g)     swap (x, y) = (y, x)+    p' c d = p'' (Map.lookup c (contents g))+                 (Map.lookup d (contents g))+    p'' (Just e) (Just f) = p e f+    p'' (Just e) Nothing  = n e+    p'' Nothing (Just e)  = n e+    p'' _        _        = False +edgesP :: (a -> a -> Bool) -> Grid Square a -> [Edge]+edgesP p g = edgesGen p (const False) g++dualEdgesP :: (a -> a -> Bool) -> Grid Square a -> [Edge]+dualEdgesP p g = [ E pt H | pt <- hedges ] +++                 [ E pt V | pt <- vedges ]+  where+    edges' f (sx, sy) = [ (x, y) | x <- [0 .. sx - 2]+                                 , y <- [0 .. sy - 1]+                                 , p' (f (x, y)) (f (x + 1, y)) ]++    hedges = edges' id (size g)+    vedges = map swap $ edges' swap (swap . size $ g)+    swap (x, y) = (y, x)+    p' c d = p'' (Map.lookup c (contents g))+                 (Map.lookup d (contents g))+    p'' (Just e) (Just f) = p e f+    p'' _        _        = False++-- | The inner edges of a grid that separate unequal cells.+borders :: Eq a => Grid Square a -> [Edge]+borders = edgesP (/=)+ -- | Clues along the outside of a square grid. data OutsideClues a = OC { left :: [a], right :: [a], bottom :: [a], top :: [a] }     deriving (Show, Eq)@@ -96,18 +126,35 @@     fmap f (OC l r b t) = OC (fmap f l) (fmap f r) (fmap f b) (fmap f t)  outsideSize :: OutsideClues a -> (Int, Int)-outsideSize (OC l _ _ t) = (length t, length l)+outsideSize (OC l r b t) = ( max (length t) (length b)+                           , max (length l) (length r)+                           ) +data OutsideClue a = OClue+    { ocBase  :: (Int, Int)+    , ocDir   :: (Int, Int)+    , ocValue :: a+    }++instance Functor OutsideClue where+    fmap f (OClue b d x) = OClue b d (f x)++outsideClueList :: OutsideClues a -> [OutsideClue a]+outsideClueList o@(OC l r b t) =+    concat+       [ zipWith (\ y c -> OClue (0,y)   (-1, 0) c) [0..h-1] l+       , zipWith (\ y c -> OClue (w-1,y) ( 1, 0) c) [0..h-1] r+       , zipWith (\ x c -> OClue (x,0)   ( 0,-1) c) [0..w-1] b+       , zipWith (\ x c -> OClue (x,h-1) ( 0, 1) c) [0..w-1] t+       ]+  where+    (w, h) = outsideSize o+ -- | Convert outside clues to association list mapping coordinate to value. outsideClues :: OutsideClues (Maybe a) -> [((Int, Int), a)]-outsideClues o@(OC l r b t) = mapMaybe liftMaybe . concat $-                             [ zipWith (\ y c -> ((-1, y), c)) [0..h-1] l-                             , zipWith (\ y c -> (( w, y), c)) [0..h-1] r-                             , zipWith (\ x c -> (( x,-1), c)) [0..w-1] b-                             , zipWith (\ x c -> (( x, h), c)) [0..w-1] t-                             ]+outsideClues = mapMaybe (liftMaybe . toCell) . outsideClueList   where-    (w, h) = outsideSize o+    toCell (OClue (bx, by) (dx, dy) v) = ((bx + dx, by + dy), v)     liftMaybe (p, Just x)  = Just (p, x)     liftMaybe (_, Nothing) = Nothing 
src/Data/Puzzles/GridShape.hs view
@@ -25,9 +25,9 @@ --   The bottom-left corner is vertex (0, 0), the bottom-left --   cell is cell (0, 0). data Square = Square !Int !Int-    deriving Show+    deriving (Show, Eq) -squareNeighbours :: [(Int, Int)] -> Square -> (Cell Square) -> [Cell Square]+squareNeighbours :: [(Int, Int)] -> Square -> Cell Square -> [Cell Square] squareNeighbours deltas (Square w h) c = filter inBounds . map (add c) $ deltas   where     inBounds (x, y) = x >= 0 && x < w && y >= 0 && y < h@@ -74,7 +74,7 @@  -- | The edge between two neighbouring cells, with the first cell --   on the left.-orientedEdge :: (Cell Square) -> (Cell Square) -> (Edge' (Vertex Square))+orientedEdge :: Cell Square -> Cell Square -> Edge' (Vertex Square) orientedEdge (x,y) (x',y')     | x' == x && y' == y+1  = E' (x,y+1) R     | x' == x && y' == y-1  = E' (x+1,y) L@@ -97,4 +97,4 @@         nbrs = [ c ^+^ d | d <- [(-1,0), (0,1), (1,0), (0,-1)] ]         (ni, no) = partition isc nbrs         newout = map (orientedEdge c) no-        newin = map (orientedEdge c) . filter ((>=) c) $ ni+        newin = map (orientedEdge c) . filter (c >=) $ ni
src/Data/Puzzles/PuzzleTypes.hs view
@@ -4,8 +4,9 @@ -- List of specific puzzle types.  module Data.Puzzles.PuzzleTypes (-    PuzzleType(..),-    lookupType,+    PuzzleType(..)+  , lookupType+  , typeNames   ) where  import Data.Tuple (swap)@@ -33,13 +34,15 @@                 | Compass                 | BoxOf2Or3                 | AfternoonSkyscrapers-                | CountNumbers+                | MeanderingNumbers                 | Tapa                 | JapaneseSums                 | Coral                 | MaximalLengths                 | PrimePlace                 | Labyrinth+                | Bahnhof+                | Cave     deriving (Show, Eq)  typeNames :: [(PuzzleType, String)]@@ -65,13 +68,15 @@             , (Compass, "compass")             , (BoxOf2Or3, "boxof2or3")             , (AfternoonSkyscrapers, "afternoonskyscrapers")-            , (CountNumbers, "countnumbers")+            , (MeanderingNumbers, "meanderingnumbers")             , (Tapa, "tapa")             , (JapaneseSums, "japanesesums")             , (Coral, "coral")             , (MaximalLengths, "maximallengths")             , (PrimePlace, "primeplace")             , (Labyrinth, "magiclabyrinth")+            , (Bahnhof, "bahnhof")+            , (Cave, "cave")             ]  -- | Look up a puzzle type by name.
src/Data/Puzzles/Pyramid.hs view
@@ -107,23 +107,23 @@                   let (ks, cs) = unzip kcs in return (ks, c:cs)  pkropki :: GenParser Char st KropkiDot-pkropki = (char '*' >> return Black)-          <|> (char 'o' >> return White)-          <|> (char ' ' >> return None)+pkropki = (char '*' >> return KBlack)+          <|> (char 'o' >> return KWhite)+          <|> (char ' ' >> return KNone)  toParser :: GenParser a () b -> [a] -> Yaml.Parser b toParser p v = case parse p "(unknown)" v of Left e  -> fail (show e)                                              Right x -> pure x  instance FromJSON Pyramid where-    parseJSON (String t) = Pyr <$> (mapM (toParser prow . T.unpack) $ T.lines t)+    parseJSON (String t) = Pyr <$> mapM (toParser prow . T.unpack) (T.lines t)     parseJSON _          = empty  instance FromJSON RowKropkiPyramid where-    parseJSON (String t) = KP <$> (mapM (toParser pkropkirow . T.unpack) $ T.lines t)+    parseJSON (String t) = KP <$> mapM (toParser pkropkirow . T.unpack) (T.lines t)     parseJSON _          = empty  instance FromJSON PyramidSol where     parseJSON (String t) = PyramidSol <$>-                           (mapM (toParser pplainrow . T.unpack) $ T.lines t)+                             mapM (toParser pplainrow . T.unpack) (T.lines t)     parseJSON _          = empty
+ src/Diagrams/Puzzles/CmdLine.hs view
@@ -0,0 +1,67 @@+{-# LANGUAGE FlexibleContexts, CPP #-}++module Diagrams.Puzzles.CmdLine +    ( B+    , renderToFile+    , RenderOpts(..)+    , formats+    , checkFormat+    , checkType+    , exitErr+    , readPuzzle+    )+  where++import Diagrams.Prelude hiding (value, option, (<>), Result)++#ifdef CAIRO+import Diagrams.Backend.Cairo (B, renderCairo)+#else+import Diagrams.Backend.SVG (B, renderSVG)+#endif++import Text.Puzzles.Puzzle+import Data.Puzzles.PuzzleTypes++import System.Exit++import Control.Monad (unless)+import qualified Data.Yaml as Y++data RenderOpts = RenderOpts { _file :: FilePath, _w :: Double }++renderB :: FilePath -> SizeSpec2D -> Diagram B R2 -> IO ()+renderB =+#ifdef CAIRO+    renderCairo+#else+    renderSVG+#endif++renderToFile :: RenderOpts -> Diagram B R2 -> IO ()+renderToFile ropts = renderB (_file ropts) (Width $ _w ropts)++formats :: [String]+#ifdef CAIRO+formats = ["png", "svg", "ps", "pdf"]+#else+formats = ["svg"]+#endif++checkFormat :: String -> IO ()+checkFormat f = unless (f `elem` formats) $+                    exitErr $ "unknown format: " ++ f++checkType :: Maybe String -> IO PuzzleType+checkType mt = do+    t <- maybe errno return mt+    maybe (errunk t) return (lookupType t)+  where+    errno    = exitErr "no puzzle type given"+    errunk t = exitErr $ "unknown puzzle type: " ++ t++readPuzzle :: FilePath -> IO (Either Y.ParseException TypedPuzzle)+readPuzzle = Y.decodeFileEither++exitErr :: String -> IO a+exitErr e = putStrLn e >> exitFailure
src/Diagrams/Puzzles/Draw.hs view
@@ -1,4 +1,6 @@-{-# LANGUAGE MultiParamTypeClasses, FlexibleContexts #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE ConstraintKinds #-}  module Diagrams.Puzzles.Draw (     PuzzleSol,@@ -25,7 +27,7 @@  -- | Optionally render the puzzle, its solution, or a side-by-side --   example with puzzle and solution.-draw :: (Backend b R2, Renderable (Path R2) b) =>+draw :: Backend' b =>         PuzzleSol b -> OutputChoice -> Maybe (Diagram b R2) draw (p, ms) = fmap (bg white) . d   where@@ -49,10 +51,10 @@     wpix = round (gridresd * w) :: Int  -- grid square size 40px     wpt = cmtopoint (0.8 * w)     -- grid square size 0.8cm -alignPixel :: (Backend b R2, Renderable (Path R2) b) => Diagram b R2 -> Diagram b R2+alignPixel :: Backend' b => Diagram b R2 -> Diagram b R2 alignPixel = scale (1/gridresd) . align' . scale gridresd   where-    align' d = maybe id grow (getCorners $ boundingBox d) $ d+    align' d = maybe id grow (getCorners $ boundingBox d) d     grow (bl, tr) = mappend $ phantoml (nudge bl False) (nudge tr True)     nudge p dir = let (px, py) = unp2 p in p2 (nudge' px dir, nudge' py dir)     nudge' x True  = fromIntegral (ceiling (x - 0.5) :: Int) + 0.5@@ -60,6 +62,6 @@     phantoml p q = phantom' $ p ~~ q  -- | Add a phantom border of the given width around a diagram.-border :: (Backend b R2, Renderable (Path R2) b) => Double -> Diagram b R2 -> Diagram b R2+border :: Backend' b => Double -> Diagram b R2 -> Diagram b R2 border w = extrudeEnvelope (w *^ unitX) . extrudeEnvelope (-w *^ unitX)          . extrudeEnvelope (w *^ unitY) . extrudeEnvelope (-w *^ unitY)
src/Diagrams/Puzzles/Elements.hs view
@@ -1,4 +1,7 @@-{-# LANGUAGE MultiParamTypeClasses, FlexibleContexts #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE ConstraintKinds #-}  -- | Module: Diagrams.TwoD.Puzzles.Elements --@@ -17,14 +20,14 @@ import Diagrams.Puzzles.Widths import Diagrams.Puzzles.Grid -pearl :: (Renderable (Path R2) b, Backend b R2) =>+pearl :: Backend' b =>          MasyuPearl -> Diagram b R2-pearl m = circle 0.35 # lw 0.05 # fc (c m)+pearl m = circle 0.35 # lwG 0.05 # fc (c m)   where     c MWhite = white     c MBlack = black -smallPearl :: (Renderable (Path R2) b, Backend b R2) =>+smallPearl :: Backend' b =>               MasyuPearl -> Diagram b R2 smallPearl = scale 0.4 . pearl @@ -41,13 +44,13 @@ cross = ur <> dr  -- | Draw a cross.-drawCross :: Renderable (Path R2) b => Diagram b R2-drawCross = stroke cross # scale 0.8 # lw edgewidth+drawCross :: Backend' b => Diagram b R2+drawCross = stroke cross # scale 0.8 # lwG edgewidth  -- | Draw a Compass clue.-drawCompassClue :: (Renderable (Path R2) b, Backend b R2) =>+drawCompassClue :: Backend' b =>                    CompassC -> Diagram b R2-drawCompassClue (CC n e s w) = texts <> stroke cross # lw onepix+drawCompassClue (CC n e s w) = texts <> stroke cross # lwG onepix     where tx Nothing _ = mempty           tx (Just x) v = text' (show x) # scale 0.5 # translate (r2 v)           texts = mconcat . zipWith tx [n, e, s, w] $@@ -56,72 +59,72 @@  -- | Draw a thermometer, given by a list of bottom-left corners -- of square cells.-thermo :: Renderable (Path R2) b => [P2] -> QDiagram b R2 Any+thermo :: Backend' b => [P2] -> QDiagram b R2 Any thermo vs@(v:_) = (bulb `atop` line) # col # translate (r2 (0.5, 0.5))     where bulb = circle 0.4 # moveTo v           line = strokeLocLine (fromVertices vs)-                 # lw 0.55 # lineCap LineCapSquare+                 # lwG 0.55 # lineCap LineCapSquare           col = lc gr . fc gr           gr = blend 0.6 white black thermo [] = error "invalid empty thermometer"  -- | Draw a list of thermometers, given as lists of @(Int, Int)@ cell -- coordinates.-drawThermos :: Renderable (Path R2) b => [Thermometer] -> QDiagram b R2 Any+drawThermos :: Backend' b => [Thermometer] -> QDiagram b R2 Any drawThermos = mconcat . map (thermo . map p2i)  -- | @drawTight d t@ draws the tight-fit value @t@, using @d@ to -- draw the components.-drawTight :: (Renderable (Path R2) b, Backend b R2) =>+drawTight :: Backend' b =>              (a -> Diagram b R2) -> Tightfit a -> Diagram b R2 drawTight d (Single x) = d x-drawTight d (UR x y) = stroke ur # lw onepix+drawTight d (UR x y) = stroke ur # lwG onepix                        <> d x # scale s # translate (r2 (-t,t))                        <> d y # scale s # translate (r2 (t,-t))     where t = 1/5           s = 2/3-drawTight d (DR x y) = stroke dr # lw onepix+drawTight d (DR x y) = stroke dr # lwG onepix                        <> d x # scale s # translate (r2 (-t,-t))                        <> d y # scale s # translate (r2 (t,t))     where t = 1/5           s = 2/3  -- | Stack the given words, left-justified.-stackWords :: (Backend b R2, Renderable (Path R2) b) => [String] -> QDiagram b R2 Any+stackWords :: Backend' b => [String] -> QDiagram b R2 Any stackWords = vcat' with {_sep = 0.1} . scale 0.8 . map (alignL . text')  -- | Mark a word in a grid of letters.-drawMarkedWord :: (Renderable (Path R2) b) => MarkedWord -> QDiagram b R2 Any-drawMarkedWord (MW s e) = lw onepix . stroke $ expandTrail' with {_expandCap = LineCapRound} 0.4 t+drawMarkedWord :: Backend' b => MarkedWord -> QDiagram b R2 Any+drawMarkedWord (MW s e) = lwG onepix . stroke $ expandTrail' with {_expandCap = LineCapRound} 0.4 t     where t = fromVertices [p2i s, p2i e] # translate (r2 (1/2,1/2))  -- | Apply 'drawMarkedWord' to a list of words.-drawMarkedWords :: (Renderable (Path R2) b) => [MarkedWord] -> QDiagram b R2 Any+drawMarkedWords :: Backend' b => [MarkedWord] -> QDiagram b R2 Any drawMarkedWords = mconcat . map drawMarkedWord  -- | Draw a slalom clue.-drawSlalomClue :: (Show a, Renderable (Path R2) b, Backend b R2) =>+drawSlalomClue :: (Show a, Backend' b) =>                   a -> Diagram b R2 drawSlalomClue x = text' (show x) # scale 0.75-                   <> circle 0.4 # fc white # lw onepix+                   <> circle 0.4 # fc white # lwG onepix  -- | Draw text. Shouldn't be more than two characters or so to fit a cell.-drawText :: (Backend b R2, Renderable (Path R2) b) => String -> QDiagram b R2 Any+drawText :: Backend' b => String -> QDiagram b R2 Any drawText = text'  -- | Draw an @Int@.-drawInt :: (Renderable (Path R2) b, Backend b R2) =>+drawInt :: Backend' b =>            Int -> Diagram b R2 drawInt s = drawText (show s)  -- | Draw a character.-drawChar :: (Renderable (Path R2) b, Backend b R2) =>+drawChar :: Backend' b =>             Char -> Diagram b R2 drawChar c = drawText [c]  -- | Stack a list of words into a unit square. Scaled such that at least -- three words will fit.-drawWords :: (Renderable (Path R2) b, Backend b R2) =>+drawWords :: Backend' b =>              [String] -> Diagram b R2 drawWords ws = spread (-1.0 *^ unitY)                       (map (centerXY . scale 0.4 . drawText) ws)@@ -129,22 +132,22 @@  -- | Fit a line drawing into a unit square. --   For example, a Curve Data clue.-drawCurve :: Renderable (Path R2) b => [Edge] -> Diagram b R2-drawCurve = lw onepix . fit 0.6 . centerXY . mconcat . map (stroke . edge)+drawCurve :: Backend' b => [Edge] -> Diagram b R2+drawCurve = lwG onepix . fit 0.6 . centerXY . mconcat . map (stroke . edge)  -- | Draw a shadow in the style of Afternoon Skyscrapers.-drawShade :: Renderable (Path R2) b => Shade -> Diagram b R2+drawShade :: Backend' b => Shade -> Diagram b R2 drawShade (Shade s w) = (if s then south else mempty) <>                         (if w then west else mempty)   where     shape = translate (r2 (-1/2, -1/2)) . fromVertices . map p2 $         [ (0, 0), (1/4, 1/4), (1, 1/4), (1, 0), (0, 0) ]-    south = strokeLocLoop shape # lw 0 # fc gray+    south = strokeLocLoop shape # lwG 0 # fc gray     west = reflectAbout (p2 (0, 0)) (r2 (1, 1)) south  -- | Draws the digits of a tapa clue, ordered --   left to right, top to bottom.-drawTapaClue :: (Backend b R2, Renderable (Path R2) b) =>+drawTapaClue :: Backend' b =>                 TapaClue -> Diagram b R2 drawTapaClue (TapaClue [x]) = drawInt x drawTapaClue (TapaClue xs)  = fit 0.8@@ -159,11 +162,17 @@     p' 1 = error "singleton clues handled separately"     p' _ = error "invalid tapa clue" -drawPrimeDiag :: (Backend b R2, Renderable (Path R2) b) =>+drawPrimeDiag :: Backend' b =>                  PrimeDiag -> Diagram b R2-drawPrimeDiag (PrimeDiag d) = stroke p # lw (3 * onepix) # lc (blend 0.5 gray white)+drawPrimeDiag (PrimeDiag d) = stroke p # lwG (3 * onepix) # lc (blend 0.5 gray white)   where     p = case d of (False, False) -> mempty                   (True,  False) -> ur                   (False, True)  -> dr                   (True,  True)  -> ur <> dr++drawCrossing :: Backend' b => Crossing -> Diagram b R2+drawCrossing = const $ drawChar '+'++drawBahnhofClue :: Backend' b => BahnhofClue -> Diagram b R2+drawBahnhofClue = either drawInt drawCrossing
src/Diagrams/Puzzles/Grid.hs view
@@ -1,4 +1,5 @@ {-# LANGUAGE MultiParamTypeClasses, FlexibleContexts, TypeFamilies #-}+{-# LANGUAGE ConstraintKinds #-}  module Diagrams.Puzzles.Grid where @@ -14,11 +15,11 @@ import Diagrams.Puzzles.Widths  -- | Draw a small black dot with no envelope.-dot :: (Renderable (Path R2) b, Backend b R2) => Diagram b R2+dot :: Backend' b => Diagram b R2 dot = circle 0.05 # fc black # smash  -- | Draw a Slither Link style grid of dots of the specified size.-slithergrid :: (Backend b R2, Renderable (Path R2) b) =>+slithergrid :: Backend' b =>                Size -> Diagram b R2 slithergrid (x, y) =     hcatsep . replicate (x + 1) . vcatsep . replicate (y + 1) $ dot@@ -41,36 +42,39 @@     fence' n l = fence (map fromIntegral [0..n]) (fromIntegral l)  -- | Draw a frame around the outside of a rectangle.-outframe :: Renderable (Path R2) b => Size -> Diagram b R2-outframe (w, h) = strokePointLoop r # lw fw+outframe' :: Backend' b => Double -> Size -> Diagram b R2+outframe' f (w, h) = strokePointLoop r # lwG fw     where wd = fromIntegral w           hd = fromIntegral h           strokePointLoop = strokeLocTrail . mapLoc (wrapLoop . closeLine)                             . fromVertices . map p2-          fw = framewidthfactor * gridwidth+          fw = f * gridwidth           e = fw / 2 - gridwidth / 2           r = [(-e, -e), (wd + e, -e), (wd + e, hd + e), (-e, hd + e)] +outframe :: Backend' b => Size -> Diagram b R2+outframe = outframe' framewidthfactor+ -- | Draw a square grid, applying the given style to the grid lines.-grid' :: (Backend b R2, Renderable (Path R2) b) =>+grid' :: Backend' b =>          (Diagram b R2 -> Diagram b R2) -> Size -> Diagram b R2 grid' gridstyle s =     outframe s-    <> stroke (gridlines s) # lw gridwidth # gridstyle+    <> stroke (gridlines s) # lwG gridwidth # gridstyle  -- | Draw a square grid with default grid line style.-grid :: (Backend b R2, Renderable (Path R2) b) =>+grid :: Backend' b =>         Size -> Diagram b R2 grid = grid' id  -- | Draw a square grid with thin frame.-plaingrid :: (Backend b R2, Renderable (Path R2) b) =>+plaingrid :: Backend' b =>              Size -> Diagram b R2-plaingrid s = stroke (fullgridlines s) # lw gridwidth+plaingrid s = stroke (fullgridlines s) # lwG gridwidth -bgdashing :: (Semigroup a, HasStyle a) =>+bgdashingG :: (Semigroup a, HasStyle a, V a ~ R2) =>              [Double] -> Double -> Colour Double -> a -> a-bgdashing ds offs c x = x # dashing ds offs <> x # lc c+bgdashingG ds offs c x = x # dashingG ds offs <> x # lc c  dashes :: [Double] dashes = [5 / 40, 3 / 40]@@ -78,14 +82,17 @@ dashoffset :: Double dashoffset = 2.5 / 40 +gridDashing :: (Semigroup a, HasStyle a, V a ~ R2) => a -> a+gridDashing = bgdashingG dashes dashoffset white'+  where+    white' = blend 0.95 white black+ -- | Draw a square grid with dashed grid lines. The gaps --   between dashes are off-white to aid in using filling --   tools.-dashedgrid :: (Backend b R2, Renderable (Path R2) b) =>+dashedgrid :: Backend' b =>               Size -> Diagram b R2-dashedgrid = grid' $ bgdashing dashes dashoffset white'-  where-    white' = blend 0.95 white black+dashedgrid = grid' gridDashing  edgePath :: Edge' (Vertex Square) -> Path R2 edgePath (E' v R) = p2i v ~~ p2i (v ^+^ (1,0))@@ -96,13 +103,13 @@ irregularGridPaths :: SGrid a -> (Path R2, Path R2) irregularGridPaths (Grid _ m) = (toPath outer, toPath inner)   where-    (outer, inner) = edges (M.keysSet m) (flip M.member m)+    (outer, inner) = edges (M.keysSet m) (`M.member` m)     toPath = mconcat . map edgePath -irregularGrid :: (Backend b R2, Renderable (Path R2) b) =>+irregularGrid :: Backend' b =>                  SGrid a -> Diagram b R2-irregularGrid g = stroke outer # lw (3 * gridwidth) # lineCap LineCapSquare <>-                  stroke inner # lw gridwidth+irregularGrid g = stroke outer # lwG (3 * gridwidth) # lineCap LineCapSquare <>+                  stroke inner # lwG gridwidth   where     (outer, inner) = irregularGridPaths g @@ -133,42 +140,83 @@ dualEdge :: Edge -> Path R2 dualEdge = translate (r2 (1/2, 1/2)) . edge -edgeStyle :: HasStyle a => a -> a-edgeStyle = lineCap LineCapSquare . lw edgewidth+edgeStyle :: (HasStyle a, V a ~ R2) => a -> a+edgeStyle = lineCap LineCapSquare . lwG edgewidth -thinEdgeStyle :: HasStyle a => a -> a-thinEdgeStyle = lineCap LineCapSquare . lw onepix+thinEdgeStyle :: (HasStyle a, V a ~ R2) => a -> a+thinEdgeStyle = lineCap LineCapSquare . lwG onepix -drawEdges :: Renderable (Path R2) b => [Edge] -> Diagram b R2+drawEdges :: Backend' b => [Edge] -> Diagram b R2 drawEdges = edgeStyle . stroke . mconcat . map edge -drawDualEdges :: Renderable (Path R2) b => [Edge] -> Diagram b R2+drawDualEdges :: Backend' b => [Edge] -> Diagram b R2 drawDualEdges = edgeStyle . stroke . mconcat . map dualEdge -drawThinDualEdges :: Renderable (Path R2) b => [Edge] -> Diagram b R2+drawThinDualEdges :: Backend' b => [Edge] -> Diagram b R2 drawThinDualEdges = thinEdgeStyle . stroke . mconcat . map dualEdge -drawAreaGrid :: (Backend b R2, Renderable (Path R2) b, Eq a) =>+drawAreaGrid :: (Backend' 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+fillBG :: Backend' b => Colour Double -> Diagram b R2+fillBG c = square 1 # lwG onepix # fc c # lc c -shadeGrid :: (Backend b R2, Renderable (Path R2) b) =>+shadeGrid :: Backend' b =>               SGrid (Maybe (Colour Double)) -> Diagram b R2 shadeGrid = mconcat . atCentres' . fmap (maybe mempty fillBG) -drawShadedGrid :: (Backend b R2, Renderable (Path R2) b) =>+drawShadedGrid :: Backend' 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) =>+drawAreaGridGray :: Backend' b =>                     SGrid Char -> Diagram b R2 drawAreaGridGray = drawAreaGrid <> shadeGrid . fmap cols   where     cols c | isUpper c  = Just (blend 0.1 black white)            | otherwise  = Nothing++irregAreaGridX :: Backend' b =>+                      SGrid Char -> Diagram b R2+irregAreaGridX = irregularGrid <> drawEdges . borders <> shadeGrid . fmap cols+  where+    cols 'X' = Just gray+    cols _   = Nothing++-- Place a list of diagrams along a ray, with steps of size+-- @f@.+distrib :: (Transformable c, Monoid c, V c ~ R2) =>+           R2 -> (Int, Int) -> Double -> [c] -> c+distrib base dir f xs =+    translate (0.75 *^ dir' ^+^ base) . mconcat $+        zipWith (\i d -> translate (fromIntegral i *^ dir') d) [(0 :: Int)..] xs+  where+    dir' = f *^ r2i dir++outsideGen :: (Transformable c, Monoid c, V c ~ R2) =>+              (OutsideClue [c] -> R2) -> Double -> [OutsideClue [c]] -> c+outsideGen tobase f ocs = mconcat . map placeOC $ ocs+  where+    placeOC o = distrib (tobase o) (ocDir o) f (ocValue o)++outsideCells :: (Transformable c, Monoid c, V c ~ R2) =>+                Double -> [OutsideClue [c]] -> c+outsideCells = outsideGen base+  where+    base (OClue (bx, by) (dx, dy) _)+        | dx /= 0   = r2 (fromIntegral bx - 1, fromIntegral by - 1/2)+        | dy /= 0   = r2 (fromIntegral bx - 1/2, fromIntegral by)+        | otherwise = error "invalid outside clue"++outsideVertices :: (Transformable c, Monoid c, V c ~ R2) =>+                   Double -> [OutsideClue [c]] -> c+outsideVertices = outsideGen base+  where+    base (OClue (bx, by) (dx, dy) _)+        | dx /= 0   = r2 (fromIntegral bx, fromIntegral by)+        | dy /= 0   = r2 (fromIntegral bx, fromIntegral by)+        | otherwise = error "invalid outside clue"
src/Diagrams/Puzzles/Lib.hs view
@@ -1,15 +1,20 @@ {-# LANGUAGE MultiParamTypeClasses, FlexibleContexts, TypeFamilies #-}+{-# LANGUAGE ConstraintKinds #-}  module Diagrams.Puzzles.Lib where  import Diagrams.Prelude  import Graphics.SVGFonts.ReadFont- import Control.Arrow ((***)) +import Paths_puzzle_draw (getDataFileName)+import System.IO.Unsafe (unsafePerformIO)++type Backend' b = (Backend b R2, Renderable (Path R2) b)+ -- | Vertical/horizontal stroked line of given length.-vline, hline :: Renderable (Path R2) b => Double -> Diagram b R2+vline, hline :: Backend' b => Double -> Diagram b R2 vline n = strokeLine . fromVertices . map p2 $ [(0, 0), (0, n)] hline n = strokeLine . fromVertices . map p2 $ [(0, 0), (n, 0)] @@ -23,8 +28,8 @@ vcatsep = cat' (r2 (0,1)) with {_sep = 1}  -- | Collapse the envelope to a point.-smash :: Backend b R2 => QDiagram b R2 Any -> QDiagram b R2 Any-smash = withEnvelope (vrule 0 :: D R2)+smash :: Backend' b => QDiagram b R2 Any -> QDiagram b R2 Any+smash = withEnvelope (pointDiagram origin :: D R2)  -- | Helper to translate by a point given as @(Int, Int)@. translatep :: (Transformable t, V t ~ R2) => (Int, Int) -> t -> t@@ -47,7 +52,7 @@ interleave (x:xs) ys = x : interleave ys xs  -- | Spread diagrams evenly along the given vector.-spread :: (Backend b R2) => R2 -> [Diagram b R2] -> Diagram b R2+spread :: Backend' b => R2 -> [Diagram b R2] -> Diagram b R2 spread v things = cat v . interleave (repeat (strut vgap)) $ things     where ds = map (diameter v) things           gap' = (magnitude v - sum ds) / fromIntegral (length things + 1)@@ -61,13 +66,13 @@  -- | Place the second diagram to the right of the first, aligning both -- vertically. The origin is the origin of the left diagram.-besidesL :: (Semigroup m, Backend b R2, Monoid m, Renderable (Path R2) b) =>+besidesL :: (Backend' b, Semigroup m, Monoid m) =>             QDiagram b R2 m -> QDiagram b R2 m -> QDiagram b R2 m besidesL a b = a ||| strutX 0.5 ||| b'     where b' = b # centerY # translate (dmid a *^ unitY)  -- | Variant of 'besidesL' where the origin is that of the right diagram.-besidesR :: (Semigroup m, Backend b R2, Monoid m, Renderable (Path R2) b) =>+besidesR :: (Backend' b, Semigroup m, Monoid m) =>            QDiagram b R2 m -> QDiagram b R2 m -> QDiagram b R2 m besidesR b a =  b' ||| strutX 0.5 ||| a     where b' = b # centerY # translate (dmid a *^ unitY)@@ -82,17 +87,20 @@ -- | Write text that is centered both vertically and horizontally and that -- has an envelope. Sized such that single capital characters fit nicely -- into a square of size @1@.-text' :: (Renderable (Path R2) b, Backend b R2) => String -> Diagram b R2-text' t = stroke (textSVG' $ TextOpts t bit INSIDE_H KERN False 1 1)-          # lw 0 # fc black # scale 0.8+text' :: Backend' b => String -> Diagram b R2+text' t = stroke (textSVG' $ TextOpts t fnt INSIDE_H KERN False 1 1)+          # lwG 0 # fc black # scale 0.8+  where+    fnt = outlMap . unsafePerformIO . getDataFileName+        $ "data/fonts/gen-light.svg"  -- text' t = text t # fontSize 0.8 # font "Helvetica" # translate (r2 (0.04, -0.07)) --          <> phantom' (textrect t)---textrect :: (Renderable (Path R2) b, Backend b R2) => String -> Diagram b R2+--textrect :: Backend' b => String -> Diagram b R2 --textrect t = rect (fromIntegral (length t) * 0.4) 0.7 # lc red---text'' :: (Renderable (Path R2) b, Backend b R2) => String -> Diagram b R2+--text'' :: Backend' b => String -> Diagram b R2 --text'' t = text' t `atop` textrect t  -- | Variant of 'phantom' that forces the argument backend type.-phantom' :: (Backend b R2) => D R2 -> Diagram b R2+phantom' :: Backend' b => Diagram b R2 -> Diagram b R2 phantom' = phantom
src/Diagrams/Puzzles/PuzzleGrids.hs view
@@ -1,6 +1,7 @@ {-# LANGUAGE MultiParamTypeClasses     #-} {-# LANGUAGE FlexibleContexts          #-} {-# LANGUAGE TypeFamilies              #-}+{-# LANGUAGE ConstraintKinds           #-}  module Diagrams.Puzzles.PuzzleGrids where @@ -15,82 +16,78 @@ import Diagrams.Puzzles.Widths import Diagrams.Puzzles.Elements -drawFillo :: (Backend b R2, Renderable (Path R2) b) =>-             SGrid (Clue Int) -> Diagram b R2-drawFillo = drawIntClues <> dashedgrid . size--drawClueGrid :: (Backend b R2, Renderable (Path R2) b) =>+drawClueGrid :: Backend' b =>                 SGrid (Clue Char) -> Diagram b R2 drawClueGrid = atCentres drawChar . clues <> grid . size -drawIntClues :: (Backend b R2, Renderable (Path R2) b) =>+drawIntClues :: Backend' b =>                 SGrid (Clue Int) -> Diagram b R2 drawIntClues = atCentres drawInt . clues -drawInts :: (Backend b R2, Renderable (Path R2) b) =>+drawInts :: Backend' b =>             SGrid Int -> Diagram b R2 drawInts = atCentres drawInt . values -drawIntGrid :: (Backend b R2, Renderable (Path R2) b) =>+drawIntGrid :: Backend' b =>                SGrid (Clue Int) -> Diagram b R2 drawIntGrid = drawIntClues <> grid . size -drawSlitherGrid :: (Backend b R2, Renderable (Path R2) b) =>+drawSlitherGrid :: Backend' b =>                    SGrid (Clue Int) -> Diagram b R2 drawSlitherGrid = atCentres drawInt . clues <> slithergrid . size -drawMasyuGrid :: (Backend b R2, Renderable (Path R2) b) =>+drawMasyuGrid :: Backend' b =>                  SGrid MasyuClue -> Diagram b R2 drawMasyuGrid = atCentres pearl . clues <> grid . size -drawCompassClues :: (Backend b R2, Renderable (Path R2) b) =>+drawCompassClues :: Backend' b =>                     SGrid CompassClue -> Diagram b R2 drawCompassClues = atCentres drawCompassClue . clues -drawCompassGrid :: (Backend b R2, Renderable (Path R2) b) =>+drawCompassGrid :: Backend' b =>                    SGrid CompassClue -> Diagram b R2 drawCompassGrid = drawCompassClues <> grid . size -sudokugrid :: (Backend b R2, Renderable (Path R2) b) =>+sudokugrid :: Backend' b =>               SGrid a -> Diagram b R2 sudokugrid = drawEdges . sudokubordersg  <> grid . size -drawWordsClues :: (Backend b R2, Renderable (Path R2) b) =>+drawWordsClues :: Backend' b =>                   SGrid (Clue [String]) -> Diagram b R2 drawWordsClues = atCentres drawWords . clues -drawTightGrid :: (Backend b R2, Renderable (Path R2) b) =>+drawTightGrid :: Backend' b =>                  (t -> Diagram b R2) -> SGrid (Tightfit t) -> Diagram b R2 drawTightGrid d g = atCentres (drawTight d) (values g)                     <> grid (size g)                     <> phantom' (stroke $ p2i (-1,-1) ~~ p2i (sx + 1, sy + 1))     where (sx, sy) = size g -drawSlalomGrid :: (Backend b R2, Renderable (Path R2) b) =>+drawSlalomGrid :: Backend' b =>                   SGrid (Clue Int) -> Diagram b R2 drawSlalomGrid g = atVertices drawSlalomClue (clues g)                    <> grid (w-1, h-1)     where (w, h) = size g -drawSlalomDiags :: (Backend b R2, Renderable (Path R2) b) =>+drawSlalomDiags :: Backend' b =>                    SGrid SlalomDiag -> Diagram b R2 drawSlalomDiags = atCentres diag . clues . fmap Just-    where diag SlalomForward  = stroke ur # lw edgewidth-          diag SlalomBackward = stroke dr # lw edgewidth+    where diag SlalomForward  = stroke ur # lwG edgewidth+          diag SlalomBackward = stroke dr # lwG edgewidth -drawCrosses ::  (Backend b R2, Renderable (Path R2) b) =>+drawCrosses ::  Backend' b =>                  SGrid Bool -> Diagram b R2 drawCrosses = atCentres (if' drawCross mempty) . values   where     if' a b x = if x then a else b  -outsideGrid :: (Backend b R2, Renderable (Path R2) b) =>+outsideGrid :: Backend' b =>                OutsideClues [String] -> Diagram b R2 outsideGrid = atCentres (scale 0.8 . drawText) . multiOutsideClues               <> grid . outsideSize -outsideIntGrid :: (Backend b R2, Renderable (Path R2) b) =>+outsideIntGrid :: Backend' b =>                   OutsideClues [Int] -> Diagram b R2 outsideIntGrid = atCentres (scale 0.8 . drawInt) . multiOutsideClues                  <> grid . outsideSize
src/Diagrams/Puzzles/PuzzleTypes.hs view
@@ -1,13 +1,16 @@ {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE ConstraintKinds #-}  module Diagrams.Puzzles.PuzzleTypes (     lits, litsplus, geradeweg, fillomino, masyu, nurikabe, latintapa,     sudoku, thermosudoku, pyramid, kpyramid, slither,     liarslither, tightfitskyscrapers, wordloop, wordsearch,     curvedata, doubleback, slalom, compass, boxof2or3,-    afternoonskyscrapers, countnumbers, tapa, japanesesums,-    coral, maximallengths, primeplace, labyrinth+    afternoonskyscrapers, meanderingnumbers, tapa, japanesesums,+    coral, maximallengths, primeplace, labyrinth, bahnhof,+    cave   ) where  import Diagrams.Prelude hiding (Loop, coral)@@ -18,48 +21,49 @@ import qualified Diagrams.Puzzles.Pyramid as DPyr import Diagrams.Puzzles.Elements import Diagrams.Puzzles.Lib+import Diagrams.Puzzles.Widths  import Data.Puzzles.Grid import Data.Puzzles.GridShape (Edge) import Data.Puzzles.Elements import qualified Data.Puzzles.Pyramid as Pyr -lits :: (Backend b R2, Renderable (Path R2) b) => RenderPuzzle b AreaGrid ShadedGrid+lits :: Backend' b => RenderPuzzle b AreaGrid ShadedGrid lits = (,)     drawAreaGridGray     (drawAreaGrid . fst <> drawShadedGrid . snd) -litsplus :: (Backend b R2, Renderable (Path R2) b) => RenderPuzzle b AreaGrid ShadedGrid+litsplus :: Backend' b => RenderPuzzle b AreaGrid ShadedGrid litsplus = lits -solstyle :: HasStyle a => a -> a-solstyle = lc (blend 0.8 black white)+solstyle :: (HasStyle a, V a ~ R2) => a -> a+solstyle = lc (blend 0.8 black white) . lwG (3 * onepix) -geradeweg :: (Backend b R2, Renderable (Path R2) b) => RenderPuzzle b IntGrid Loop+geradeweg :: Backend' b => RenderPuzzle b IntGrid Loop geradeweg = (,)     drawIntGrid     (drawIntClues . fst      <> solstyle . drawDualEdges . snd      <> grid . size . fst) -fillomino :: (Backend b R2, Renderable (Path R2) b) => RenderPuzzle b IntGrid IntGrid+fillomino :: Backend' b => RenderPuzzle b IntGrid (SGrid Int) fillomino = (,)-    drawFillo-    (drawFillo . snd)+    (atCentres drawInt . clues <> dashedgrid . size)+    ((atCentres drawInt . values <> drawEdges . borders <> dashedgrid . size) . snd) -masyu :: (Backend b R2, Renderable (Path R2) b) =>+masyu :: Backend' b =>          RenderPuzzle b (SGrid (Clue MasyuPearl)) Loop masyu = (,)     drawMasyuGrid     (solstyle . drawDualEdges . snd <> drawMasyuGrid . fst) -nurikabe :: (Backend b R2, Renderable (Path R2) b) =>+nurikabe :: Backend' b =>             RenderPuzzle b IntGrid ShadedGrid nurikabe = (,)     drawIntGrid     (drawIntGrid . fst <> drawShadedGrid . snd) -latintapa :: (Backend b R2, Renderable (Path R2) b) =>+latintapa :: Backend' b =>              RenderPuzzle b (SGrid (Clue [String])) CharClueGrid latintapa = (,)     l@@ -67,19 +71,19 @@   where     l = grid . size <> drawWordsClues -sudoku :: (Backend b R2, Renderable (Path R2) b) =>+sudoku :: Backend' b =>           RenderPuzzle b IntGrid IntGrid sudoku = (,)     (drawIntClues <> sudokugrid)     ((drawIntClues <> sudokugrid) . snd) -thermosudoku :: (Backend b R2, Renderable (Path R2) b) =>+thermosudoku :: Backend' b =>                 RenderPuzzle b (SGrid Int, [Thermometer]) IntGrid thermosudoku = (,)     (drawInts . fst <> sudokugrid . fst <> drawThermos . snd)     (drawIntClues . snd <> sudokugrid . snd <> drawThermos . snd . fst) -pyramid :: (Backend b R2, Renderable (Path R2) b) =>+pyramid :: Backend' b =>     RenderPuzzle b Pyr.Pyramid Pyr.PyramidSol pyramid = (,)     DPyr.pyramid@@ -87,7 +91,7 @@   where     merge (p, q) = Pyr.mergepyramidsol p q -kpyramid :: (Backend b R2, Renderable (Path R2) b) =>+kpyramid :: Backend' b =>     RenderPuzzle b Pyr.RowKropkiPyramid Pyr.PyramidSol kpyramid = (,)     DPyr.kpyramid@@ -95,13 +99,13 @@   where     merge (p, q) = Pyr.mergekpyramidsol p q -slither :: (Backend b R2, Renderable (Path R2) b) =>+slither :: Backend' b =>            RenderPuzzle b IntGrid Loop slither = (,)     drawSlitherGrid     (drawSlitherGrid . fst <> solstyle . drawEdges . snd) -liarslither :: (Backend b R2, Renderable (Path R2) b) =>+liarslither :: Backend' b =>                RenderPuzzle b IntGrid (Loop, SGrid Bool) liarslither = (,)     drawSlitherGrid@@ -109,7 +113,7 @@      <> drawSlitherGrid . fst      <> solstyle . drawEdges . fst . snd) -tightfitskyscrapers :: (Backend b R2, Renderable (Path R2) b) =>+tightfitskyscrapers :: Backend' b =>                        RenderPuzzle b (OutsideClues (Maybe Int), SGrid (Tightfit ()))                                       (SGrid (Tightfit Int)) tightfitskyscrapers = (,)@@ -118,49 +122,50 @@     (atCentres drawInt . outsideClues . fst . fst      <> drawTightGrid drawInt . snd) -wordgrid :: (Backend b R2, Renderable (Path R2) b) =>+wordgrid :: Backend' b =>             SGrid (Maybe Char) -> [String] -> Diagram b R2 wordgrid g ws = stackWords ws `besidesR` drawClueGrid g -wordloop :: (Backend b R2, Renderable (Path R2) b) =>+wordloop :: Backend' b =>             RenderPuzzle b (CharClueGrid, [String]) CharClueGrid wordloop = (,)     (uncurry wordgrid)     (drawClueGrid . snd) -wordsearch :: (Backend b R2, Renderable (Path R2) b) =>+wordsearch :: Backend' b =>               RenderPuzzle b (CharClueGrid, [String]) (CharClueGrid, [MarkedWord]) wordsearch = (,)     (uncurry wordgrid)      (solstyle . drawMarkedWords . snd . snd      <> drawClueGrid . fst . snd) -curvedata :: (Backend b R2, Renderable (Path R2) b) =>+curvedata :: Backend' b =>              RenderPuzzle b (SGrid (Clue [Edge])) [Edge] curvedata = (,)     cd     ((solstyle . drawDualEdges . snd) <> cd . fst)-    where cd = (atCentres drawCurve . clues <> grid . size)+  where+    cd = atCentres drawCurve . clues <> grid . size -doubleback :: (Backend b R2, Renderable (Path R2) b) =>+doubleback :: Backend' b =>               RenderPuzzle b AreaGrid Loop doubleback = (,)     drawAreaGridGray     (solstyle . drawDualEdges . snd <> drawAreaGridGray . fst) -slalom :: (Backend b R2, Renderable (Path R2) b) =>+slalom :: Backend' b =>           RenderPuzzle b IntGrid (SGrid SlalomDiag) slalom = (,)     drawSlalomGrid     (drawSlalomGrid . fst <> solstyle . drawSlalomDiags . snd) -compass :: (Backend b R2, Renderable (Path R2) b) =>+compass :: Backend' b =>            RenderPuzzle b (SGrid (Clue CompassC)) AreaGrid compass = (,)     drawCompassGrid     (drawCompassClues . fst <> drawAreaGridGray . snd) -boxof2or3 :: (Backend b R2, Renderable (Path R2) b) =>+boxof2or3 :: Backend' b =>              RenderPuzzle b (SGrid MasyuPearl, [Edge]) () boxof2or3 = (,)     (atCentres smallPearl . values . fst@@ -168,19 +173,19 @@      <> drawThinDualEdges . snd)     (error "boxof2or3 solution not implemented") -afternoonskyscrapers :: (Backend b R2, Renderable (Path R2) b) =>+afternoonskyscrapers :: Backend' b =>                         RenderPuzzle b (SGrid Shade) IntGrid afternoonskyscrapers = (,)     (grid . size <> atCentres drawShade . values)     (drawIntGrid . snd <> atCentres drawShade . values . fst) -countnumbers :: (Backend b R2, Renderable (Path R2) b) =>+meanderingnumbers :: Backend' b =>                         RenderPuzzle b AreaGrid IntGrid-countnumbers = (,)+meanderingnumbers = (,)     drawAreaGrid     (drawIntGrid . snd <> drawAreaGrid . fst) -tapa :: (Backend b R2, Renderable (Path R2) b) =>+tapa :: Backend' b =>         RenderPuzzle b (SGrid TapaClue) ShadedGrid tapa = (,)     tapaGrid@@ -188,23 +193,23 @@   where     tapaGrid = atCentres drawTapaClue . values <> grid . size -japanesesums :: (Backend b R2, Renderable (Path R2) b) =>-                RenderPuzzle b (OutsideClues [Int]) (SGrid JapVal)+japanesesums :: Backend' b =>+                RenderPuzzle b (OutsideClues [Int]) (SGrid (Either Black Int)) japanesesums = (,)     outsideIntGrid-    (japcells . snd <> outsideIntGrid . fst)+    (outsideIntGrid . fst <> japcells . snd)   where     japcells = atCentres japcell . values-    japcell JapBlack = fillBG gray-    japcell (JapInt x) = drawInt x+    japcell (Left Black) = fillBG gray+    japcell (Right x) = drawInt x -coral :: (Backend b R2, Renderable (Path R2) b) =>+coral :: Backend' b =>           RenderPuzzle b (OutsideClues [String]) ShadedGrid coral = (,)     outsideGrid-    (drawShadedGrid . snd <> outsideGrid . fst)+    (outsideGrid . fst <> drawShadedGrid . snd) -maximallengths :: (Backend b R2, Renderable (Path R2) b) =>+maximallengths :: Backend' b =>                   RenderPuzzle b (OutsideClues (Maybe Int)) Loop maximallengths = (,)     g@@ -213,7 +218,7 @@     g = atCentres drawInt . outsideClues         <> grid . outsideSize -primeplace :: (Backend b R2, Renderable (Path R2) b) =>+primeplace :: Backend' b =>               RenderPuzzle b (SGrid PrimeDiag) (SGrid Int) primeplace = (,)     g@@ -221,10 +226,32 @@   where     g = irregularGrid <> atCentres drawPrimeDiag . values -labyrinth :: (Backend b R2, Renderable (Path R2) b) =>+labyrinth :: Backend' b =>              RenderPuzzle b (SGrid (Clue Int), [Edge]) (SGrid (Clue Int)) labyrinth = (,)     (atCentres drawInt . clues . fst <> g)     (atCentres drawInt . clues . snd <> g . fst)   where     g = drawEdges . snd <> plaingrid . size . fst++bahnhof :: Backend' b =>+            RenderPuzzle b (SGrid (Maybe BahnhofClue)) [Edge]+bahnhof = (,)+    (atCentres drawBahnhofClue . clues <> grid . size)+    (atCentres drawBahnhofStation . clues . fst+     <> solstyle . drawDualEdges . snd+     <> grid . size . fst)+  where+    drawBahnhofStation = either drawInt (const mempty)++cave ::+    (Backend b R2, Renderable (Path R2) b) =>+    RenderPuzzle b (SGrid (Clue Int)) ShadedGrid+cave = (,)+    g+    (drawEdges . edgesGen (/=) not . snd+     <> drawShadedGrid . snd <> fr . fst+     <> g . fst)+  where+    g = gridDashing . plaingrid . size <> atCentres drawInt . clues+    fr gr = outframe' 8 (size gr) # lc gray
src/Diagrams/Puzzles/Pyramid.hs view
@@ -1,5 +1,6 @@ {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE ConstraintKinds #-}  module Diagrams.Puzzles.Pyramid where @@ -13,35 +14,34 @@ pgray :: Colour Double pgray = blend 0.6 white black -cell :: (Backend b R2, Renderable (Path R2) b) => Bool -> Diagram b R2-cell s = square 1 # lw onepix # if s then fc pgray else id+cell :: Backend' b => Bool -> Diagram b R2+cell s = square 1 # lwG onepix # if s then fc pgray else id -clue :: (Backend b R2, Renderable (Path R2) b) => Maybe Int -> Diagram b R2+clue :: Backend' b => Maybe Int -> Diagram b R2 clue Nothing = mempty clue (Just c) = text' (show c) -cellc :: (Backend b R2, Renderable (Path R2) b) => Bool -> Maybe Int -> Diagram b R2+cellc :: Backend' b => Bool -> Maybe Int -> Diagram b R2 cellc s c = clue c `atop` cell s -row :: (Backend b R2, Renderable (Path R2) b) => Row -> Diagram b R2+row :: Backend' b => Row -> Diagram b R2 row (R cs s) = centerX . hcat . map (cellc s) $ cs -pyramid :: (Backend b R2, Renderable (Path R2) b) => Pyramid -> Diagram b R2+pyramid :: Backend' b => Pyramid -> Diagram b R2 pyramid = alignBL . vcat . map row . unPyr -kropki :: (Backend b R2, Renderable (Path R2) b) => KropkiDot -> Diagram b R2-kropki None = mempty-kropki c = circle 0.1 # lw 0.03 # fc (col c) # smash-    where col White = white-          col Black = blend 0.98 black white-          col None  = error "can't reach"+kropki :: Backend' b => KropkiDot -> Diagram b R2+kropki KNone = mempty+kropki c = circle 0.1 # lwG 0.03 # fc (col c) # smash+    where col KWhite = white+          col KBlack = blend 0.98 black white+          col KNone  = error "can't reach" -krow :: (Backend b R2, Renderable (Path R2) b) => KropkiRow -> Diagram b R2+krow :: Backend' b => KropkiRow -> Diagram b R2 krow (KR cs s ks) = ccat dots <> ccat clues     where ccat = centerX . hcat           clues = map (cellc s) cs-          clues' = map (cellc s) cs :: [D R2]-          dots = interleave (map phantom' clues') (map kropki ks)+          dots = interleave (map phantom' clues) (map kropki ks) -kpyramid :: (Backend b R2, Renderable (Path R2) b) => RowKropkiPyramid -> Diagram b R2+kpyramid :: Backend' b => RowKropkiPyramid -> Diagram b R2 kpyramid = alignBL . vcat . map krow . unKP
src/Text/Puzzles/PuzzleTypes.hs view
@@ -5,14 +5,12 @@     sudoku, thermosudoku, pyramid, kpyramid, slither,     liarslither, tightfitskyscrapers, wordloop, wordsearch,     curvedata, doubleback, slalom, compass, boxof2or3,-    afternoonskyscrapers, countnumbers, tapa, japanesesums, coral,-    maximallengths, primeplace, labyrinth+    afternoonskyscrapers, meanderingnumbers, tapa, japanesesums, coral,+    maximallengths, primeplace, labyrinth, bahnhof, cave   ) where -import Prelude hiding (sequence)- import Control.Applicative-import Control.Monad hiding (sequence)+import Control.Monad  import Data.Yaml @@ -32,8 +30,8 @@ geradeweg :: ParsePuzzle (SGrid (Clue Int)) Loop geradeweg = (parseClueGrid, parseEdges) -fillomino :: ParsePuzzle IntGrid IntGrid-fillomino = (parseClueGrid, parseClueGrid)+fillomino :: ParsePuzzle IntGrid (SGrid Int)+fillomino = (parseClueGrid, parseExtGrid)  masyu :: ParsePuzzle (SGrid (Clue MasyuPearl)) Loop masyu = (parseClueGrid, parseEdges)@@ -42,7 +40,8 @@ nurikabe = (parseSpacedClueGrid, parseShadedGrid)  latintapa :: ParsePuzzle (SGrid (Clue [String])) (SGrid (Maybe Char))-latintapa = ((unRG <$>) . parseJSON, parseClueGrid)+latintapa = ((unRG <$>) . parseJSON,+             fmap (fmap (fmap unAlpha)) . parseClueGrid')  sudoku :: ParsePuzzle IntGrid IntGrid sudoku = (parseClueGrid, parseClueGrid)@@ -120,18 +119,20 @@ afternoonskyscrapers = (parseAfternoonGrid, parseGrid)  -- this should be changed to support clue numbers-countnumbers :: ParsePuzzle AreaGrid IntGrid-countnumbers = (parseGrid, parseGrid)+meanderingnumbers :: ParsePuzzle AreaGrid IntGrid+meanderingnumbers = (parseGrid, parseGrid)  tapa :: ParsePuzzle (SGrid TapaClue) ShadedGrid tapa = (\v -> fmap unParseTapaClue . unRG <$> parseJSON v,         parseShadedGrid) -japanesesums :: ParsePuzzle (OutsideClues [Int]) (SGrid JapVal)+japanesesums :: ParsePuzzle (OutsideClues [Int]) (SGrid (Either Black Int)) japanesesums = (parseMultiOutsideClues, parseGrid)  coral :: ParsePuzzle (OutsideClues [String]) ShadedGrid-coral = (parseMultiOutsideClues, parseShadedGrid)+coral = (,)+    (fmap (fmap (map unIntString)) . parseMultiOutsideClues)+    parseShadedGrid  maximallengths :: ParsePuzzle (OutsideClues (Maybe Int)) Loop maximallengths = (\v -> fmap blankToMaybe <$> parseCharOutside v,@@ -142,3 +143,9 @@  labyrinth :: ParsePuzzle (SGrid (Clue Int), [Edge]) (SGrid (Clue Int)) labyrinth = (parseCellEdges, parseClueGrid')++bahnhof :: ParsePuzzle (SGrid (Maybe BahnhofClue)) [Edge]+bahnhof = (parseClueGrid, parseEdges)++cave :: ParsePuzzle (SGrid (Clue Int)) ShadedGrid+cave = (parseClueGrid, parseShadedGrid)
src/Text/Puzzles/Util.hs view
@@ -2,18 +2,18 @@  module Text.Puzzles.Util where -import Prelude hiding (sequence)+import Prelude hiding (mapM)  import Control.Applicative import Control.Arrow-import Control.Monad hiding (sequence)+import Control.Monad hiding (mapM)  import Data.Hashable import Data.Maybe (catMaybes, fromMaybe) import qualified Data.Map as Map import qualified Data.HashMap.Strict as HMap-import Data.Traversable (traverse, sequence, sequenceA, Traversable)-import Data.Foldable (Foldable, fold)+import Data.Traversable (traverse, sequenceA, mapM, Traversable)+import Data.Foldable (Foldable, foldMap) import Data.Monoid ((<>)) import Data.List (intersect) @@ -27,9 +27,24 @@ import Data.Puzzles.GridShape hiding (size) import Data.Puzzles.Elements +type Path = [String]++field :: Path -> Value -> Parser Value+field = field' . map T.pack+  where+    field' [] v                = pure v+    field' (f:fs) (Object v) = v .: f >>= field' fs+    field' _  _                = empty++parseFrom :: Path -> (Value -> Parser b) -> (Value -> Parser b)+parseFrom fs p v = field fs v >>= p+ class FromChar a where     parseChar :: Char -> Parser a +failChar :: Char -> String -> Parser a+failChar c expect = fail $ "got '" ++ [c] ++ "', expected " ++ expect+ instance FromChar Char where     parseChar = pure @@ -52,6 +67,14 @@         | isAlpha c  = Alpha <$> parseChar c         | otherwise  = empty +-- | Helper to parse strings from number-formatted YAML fields.+--   Somewhat dodgy.+newtype IntString = IntString { unIntString :: String }++instance FromJSON IntString where+    parseJSON v@(Number _) = IntString . (show :: Int -> String) <$> parseJSON v+    parseJSON v            = IntString <$> parseJSON v+ -- | A rectangle. Each row has length `w`. data Rect a = Rect !Int !Int [[a]]     deriving Show@@ -66,15 +89,16 @@         w = maximum . map T.length $ ls         h = length ls         filledc = map (T.unpack . T.justifyLeft w ' ') ls-        filled = sequence . map (mapM parseChar) $ filledc-    parseJSON _          = empty+        filled = mapM (mapM parseChar) filledc+    parseJSON _          = fail "expected string"  data Border a = Border [a] [a] [a] [a]     deriving Show  -- | This instance might be a lie. instance Foldable Border where-    fold (Border l r b t) = fold l <> fold r <> fold b <> fold t+    foldMap f (Border l r b t) = foldMap f l <> foldMap f r+                              <> foldMap f b <> foldMap f t  instance Traversable Border where     sequenceA (Border l r b t) = Border <$> sequenceA l@@ -98,8 +122,8 @@             ls' = map (middle w) . middle h $ ls         mapM_ ((parseChar :: Char -> Parser Space) . flip ($) ls)               [head . head, head . last, last . head, last . last]-        lsparsed <- sequence . map (mapM parseChar) $ ls'-        bparsed  <- sequenceA . fmap parseChar $ b+        lsparsed <- mapM (mapM parseChar) ls'+        bparsed  <- mapM parseChar b         return $ BorderedRect (w-2) (h-2) lsparsed bparsed       where         middle len = take (len - 2) . drop 1@@ -114,7 +138,7 @@         w = maximum . map length $ ls         wmin = minimum . map length $ ls         h = length ls-        p = sequence . map (mapM (parseString . T.unpack)) $ ls+        p = mapM (mapM (parseString . T.unpack)) ls     parseJSON _          = empty  data Space = Space@@ -131,11 +155,24 @@     parseChar '.' = pure Blank     parseChar _   = empty +parseCharJSON :: FromChar a => Value -> Parser a+parseCharJSON v = do+    [c] <- parseJSON v+    parseChar c++instance FromJSON Blank where+   parseJSON = parseCharJSON+ instance FromChar Blank' where     parseChar '.' = pure Blank'     parseChar '-' = pure Blank'     parseChar _   = empty +instance FromJSON Blank' where+    parseJSON (String ".") = pure Blank'+    parseJSON (String "-") = pure Blank'+    parseJSON _            = empty+ instance FromChar Empty where     parseChar ' ' = pure Empty     parseChar _   = empty@@ -153,19 +190,33 @@ instance FromChar MasyuPearl where     parseChar '*' = pure MBlack     parseChar 'o' = pure MWhite-    parseChar _   = empty+    parseChar c   = failChar c "'*' or 'o'"  instance FromChar SlalomDiag where     parseChar '/'  = pure SlalomForward     parseChar '\\' = pure SlalomBackward     parseChar _    = empty +instance FromChar Black where+    parseChar 'X' = pure Black+    parseChar 'x' = pure Black+    parseChar _   = empty+ instance (FromChar a, FromChar b) => FromChar (Either a b) where     parseChar c = Left <$> parseChar c <|> Right <$> parseChar c  instance (FromString a, FromString b) => FromString (Either a b) where     parseString c = Left <$> parseString c <|> Right <$> parseString c +newtype Either' a b = Either' { unEither' :: Either a b }++instance (FromChar a, FromChar b) => FromChar (Either' a b) where+    parseChar c = Either' <$> parseChar c++instance (FromJSON a, FromJSON b) => FromJSON (Either' a b) where+    parseJSON v = Either' <$>+                      (Left <$> parseJSON v <|> Right <$> parseJSON v)+ instance FromChar a => FromChar (Maybe a) where     parseChar = optional . parseChar @@ -211,6 +262,26 @@ parseGrid :: FromChar a => Value -> Parser (SGrid a) parseGrid v = rectToSGrid <$> parseJSON v +parseGridWith :: (Char -> Parser a) -> Value -> Parser (SGrid a)+parseGridWith pChar v = traverse pChar =<< parseGrid v++parseWithReplacement :: FromChar a =>+    (Char -> Maybe a) -> Char -> Parser a+parseWithReplacement replace c = maybe (parseChar c) pure (replace c)++parseCharMap :: FromJSON a => Value -> Parser (Map.Map Char a)+parseCharMap v = do+    m <- parseJSON v+    guard . all (\k -> length k == 1) . Map.keys $ m+    return $ Map.mapKeys head m++parseExtGrid :: (FromChar a, FromJSON a) => Value -> Parser (SGrid a)+parseExtGrid v@(String _) = parseGrid v+parseExtGrid v = do+    repl <- parseFrom ["replace"] parseCharMap v+    parseFrom ["grid"] (parseGridWith+                        (parseWithReplacement (`Map.lookup` repl))) v+ parseClueGrid :: FromChar a => Value -> Parser (SGrid (Clue a)) parseClueGrid v = rectToClueGrid <$> parseJSON v @@ -271,17 +342,17 @@         return (gn', gc')     both f (x, y) = (f x, f y)     halveGrid (Grid (Square w h) m)-        | odd w && odd h = pure $ (Grid snode mnode, Grid scell mcell)-        | otherwise      = empty+        | odd w && odd h = pure (Grid snode (divkeys mnode),+                                 Grid scell (divkeys mcell))+        | otherwise      = fail "non-odd grid size"       where         w' = (w + 1) `div` 2         h' = (h + 1) `div` 2         snode = Square w' h'         scell = Square (w' - 1) (h' - 1)-        (mnode, mcell) =-            both (Map.mapKeys (both (`div` 2))) .-            Map.partitionWithKey (const . uncurry (&&) . both even) $-            m+        mnode = Map.filterWithKey (const . uncurry (&&) . both even) m+        mcell = Map.filterWithKey (const . uncurry (&&) . both odd)  m+        divkeys = Map.mapKeys (both (`div` 2))  -- | Parse a grid of edges with values at the nodes. --@@ -306,15 +377,11 @@ data HalfDirs = HalfDirs {unHalfDirs :: [Dir]}  instance FromChar HalfDirs where-    parseChar c | c == '└'        = pure . HalfDirs $ [V, H]-                | c `elem` "│┘"   = pure . HalfDirs $ [V]-                | c `elem` "─└┌"  = pure . HalfDirs $ [H]+    parseChar c | c `elem` "└┴├┼" = pure . HalfDirs $ [V, H]+                | c `elem` "│┘┤"  = pure . HalfDirs $ [V]+                | c `elem` "─┌┬"  = pure . HalfDirs $ [H]                 | otherwise       = pure . HalfDirs $ [] -instance FromChar JapVal where-    parseChar c | c `elem` ['x', 'X']  = pure JapBlack-    parseChar c = JapInt <$> parseChar c- -- parses a string like --  ┌┐┌─┐ --  ││└┐│@@ -363,8 +430,8 @@         succs' q = maybe [] (const $ succs q) (Map.lookup q m')  parseThermoGrid :: ThermoRect -> Parser (SGrid Int, [Thermometer])-parseThermoGrid (Rect w h ls) = (,) (Grid s ints) <$>-                                (parseThermos $ Grid s alphas)+parseThermoGrid (Rect w h ls) = (,) (Grid s ints)+                              <$> parseThermos (Grid s alphas)   where     s = Square w h     (ints, alphas) = partitionEithers . snd . partitionEithers $@@ -389,8 +456,8 @@  instance FromChar a => FromString (Tightfit a) where     parseString [c]           = Single <$> parseChar c-    parseString (c: '/':d:[]) = UR <$> parseChar c <*> parseChar d-    parseString (c:'\\':d:[]) = DR <$> parseChar c <*> parseChar d+    parseString [c, '/',d]    = UR <$> parseChar c <*> parseChar d+    parseString [c,'\\',d]    = DR <$> parseChar c <*> parseChar d     parseString _             = empty  parseTightIntGrid :: Value -> Parser (SGrid (Tightfit Int))@@ -436,7 +503,7 @@ hashmaptomap = Map.fromList . HMap.toList  compose :: (Ord a, Ord b) => Map.Map a b -> Map.Map b c -> Maybe (Map.Map a c)-compose m1 m2 = sequence . Map.map (flip Map.lookup m2) $ m1+compose m1 m2 = mapM (`Map.lookup` m2) m1  instance FromJSON a => FromJSON (RefGrid a) where     parseJSON (Object v) = RefGrid <$> do@@ -486,6 +553,15 @@     pfield f = parseLine . fromMaybe [] =<< v .:? f parseCharOutside _          = empty +parseOutside :: FromJSON a => Value -> Parser (OutsideClues a)+parseOutside (Object v) = reorientOutside <$>+                              (OC <$>+                               pfield "left" <*> pfield "right" <*>+                               pfield "bottom" <*> pfield "top" )+  where+    pfield f = pure . fromMaybe [] =<< v .:? f+parseOutside _          = empty+ parseMultiOutsideClues :: FromJSON a => Value -> Parser (OutsideClues [a]) parseMultiOutsideClues (Object v) = rev <$> raw   where@@ -501,3 +577,7 @@     parseChar '\\' = pure $ PrimeDiag (False, True)     parseChar 'X'  = pure $ PrimeDiag (True,  True)     parseChar _    = empty++instance FromChar Crossing where+    parseChar '+' = pure Crossing+    parseChar _   = fail "expected '+'"
+ src/tools/drawpuzzle.hs view
@@ -0,0 +1,145 @@+{-# LANGUAGE FlexibleContexts #-}++module Main where++import Diagrams.Prelude hiding (value, option, (<>), Result)++import Diagrams.Puzzles.CmdLine++import Text.Puzzles.Puzzle+import Data.Puzzles.Compose+import Data.Puzzles.PuzzleTypes (typeNames)+import Diagrams.Puzzles.Draw++import Options.Applicative+import Control.Monad+import Data.Maybe+import Data.List (intercalate, sort)++import System.FilePath+import System.Environment (getProgName)++import qualified Data.Yaml as Y++optListTypes :: Parser (a -> a)+optListTypes =+    infoOption+        (unlines' . sort . map snd $ typeNames)+        (long "list-types"+         <> help "List supported puzzle types")+  where+    unlines' = intercalate "\n"++data PuzzleOpts = PuzzleOpts+    { _format   :: String+    , _type     :: Maybe String+    , _puzzle   :: Bool+    , _solution :: Bool+    , _example  :: Bool+    , _input    :: FilePath+    }++puzzleOpts :: Parser PuzzleOpts+puzzleOpts = PuzzleOpts+    <$> strOption+            (long "format" <> short 'f'+             <> value (head formats)+             <> metavar "FMT"+             <> help ("Desired output format by file extension " ++ fmts))+    <*> (optional . strOption $+            (long "type" <> short 't'+             <> metavar "TYPE"+             <> help "Puzzle type, overriding type in input file"))+    <*> switch+            (long "puzzle" <> short 'p'+             <> help "Render puzzle (to base.ext)")+    <*> switch+            (long "solution" <> short 's'+             <> help "Render solution (to base-sol.ext)")+    <*> switch+            (long "example" <> short 'e'+             <> help "Render example (to base.ext)")+    <*> argument str+            (metavar "INPUT"+             <> help "Puzzle file in .pzl format")+  where+    fmts = "(" ++ intercalate ", " formats ++ ")"++cmtopoint :: Double -> Double+cmtopoint = (* 28.3464567)++outputSuffix :: OutputChoice -> String+outputSuffix DrawPuzzle = ""+outputSuffix DrawSolution = "-sol"+outputSuffix DrawExample = ""++toRenderOpts :: OutputChoice -> Double -> PuzzleOpts -> RenderOpts+toRenderOpts oc w opts = RenderOpts out w'+  where+    f = _format opts+    u = case f of "png" -> Pixels+                  _     -> Points+    w' = toOutputWidth u w+    base = takeBaseName (_input opts)+    out = addExtension (base ++ outputSuffix oc) f++renderPuzzle :: PuzzleOpts -> (OutputChoice -> Maybe (Diagram B R2)) ->+                (OutputChoice, Bool) -> IO ()+renderPuzzle opts r (oc, req) = do+    let x = r oc+    when (req && isNothing x) $+        exitErr ("failed to render (no solution?): " ++ show oc)+    when (isJust x) $ do+        let Just x' = x+            ropts = toRenderOpts oc (diagramWidth x') opts+        renderToFile ropts x'++defaultOpts :: Parser a -> IO a+defaultOpts optsParser = do+    prog <- getProgName+    let p = info (helper <*> optListTypes <*> optsParser)+                (fullDesc+                 <> progDesc "Command-line diagram generation."+                 <> header prog)+    execParser p++checkOutput :: PuzzleOpts -> IO [(OutputChoice, Bool)]+checkOutput opts+    | (p || s) && e  = exitErr "example output conflicts with puzzle/solution"+    | e              = return . map req $ [DrawExample]+    | p && s         = return . map req $ [DrawPuzzle, DrawSolution]+    | p              = return . map req $ [DrawPuzzle]+    | s              = return . map req $ [DrawSolution]+    | otherwise      = return [req DrawPuzzle, opt DrawSolution]+  where+    p = _puzzle opts+    s = _solution opts+    e = _example opts+    req x = (x, True)+    opt x = (x, False)++maybeSkipSolution :: [(OutputChoice, Bool)] -> Maybe Y.Value -> Maybe Y.Value+maybeSkipSolution _ Nothing    = Nothing+maybeSkipSolution ocs (Just v) =+    if any hasSol . map fst $ ocs+        then Just v+        else Nothing+  where+    hasSol DrawSolution = True+    hasSol DrawExample  = True+    hasSol DrawPuzzle   = False++main :: IO ()+main = do+    opts <- defaultOpts puzzleOpts+    ocs <- checkOutput opts+    checkFormat (_format opts)+    mp <- readPuzzle (_input opts)+    TP mt pv msv <- case mp of Left  e -> exitErr $+                                          "parse failure: " ++ show e+                               Right p -> return p+    let msv' = maybeSkipSolution ocs msv+    t <- checkType $ _type opts `mplus` mt+    let ps = Y.parseEither (handle drawPuzzleMaybeSol t) (pv, msv')+    case ps of Right ps' -> mapM_ (renderPuzzle opts (draw ps')) ocs+               Left    e -> exitErr $ "parse failure: " ++ e
tests/tests.hs view
@@ -3,16 +3,18 @@  import Data.Yaml import Data.List (sort)-+import qualified Data.Map as Map import Control.DeepSeq  import Text.Puzzles.Puzzle-import Data.Puzzles.Elements (Thermometer)-import Text.Puzzles.Util (parseChar, parseMultiOutsideClues)+import Data.Puzzles.Elements (Thermometer, MasyuPearl(..))+import Text.Puzzles.Util+    (parseChar, parseMultiOutsideClues, parseEdgeGrid) import Text.Puzzles.PuzzleTypes import qualified Data.Puzzles.Grid as Grid import Data.Puzzles.Pyramid (PyramidSol(..)) import Data.Puzzles.Grid (multiOutsideClues, OutsideClues(..))+import Data.Puzzles.GridShape (Edge(..), Square(..), Dir(..))  import Diagrams.Puzzles.PuzzleGrids import Diagrams.Prelude@@ -78,6 +80,7 @@     , testParsePzl "thermosudoku" thermosudoku thermo_2     , testNonparsePzl "thermosudoku" thermosudoku thermo_broken_1     , testNonparsePzl "thermosudoku" thermosudoku thermo_broken_2+    , testParsePzl "boxof2or3" boxof2or3 boxof2or3_1     ]  test_thermo_1 :: [Thermometer]@@ -117,6 +120,18 @@     oc = OC [[3], [1, 2]] [[1, 0], []] [[0, 0, 1]] [[1, -1]]          :: OutsideClues [Int] +test_edge_grid :: Assertion+test_edge_grid = Right (gn, gc, es) @=? res+  where+    res = parseEither parseEdgeGrid edgeGrid_1+    gn = Grid.Grid (Square 4 2) $ Map.fromList+        [((0,0),Just MBlack),((0,1),Just MWhite),((1,0),Just MWhite),((1,1),Just MBlack),+         ((2,0),Nothing),((2,1),Just MBlack),((3,0),Nothing),((3,1),Just MWhite)]+    gc :: Grid.SGrid Int+    gc = Grid.Grid (Square 3 1) $ Map.fromList+        [((0,0),1),((1,0),2),((2,0),3)]+    es = [E (0,0) H, E (0,1) H, E (1,1) H, E (2,1) H, E (0,0) V, E (1,0) V]+ parseDataTests :: TestTree parseDataTests = testGroup "Parsing tests (full puzzles, result checks)"     [ testCase "parse tightfit, correct size" $ test_tightfit_1 @? "error in puzzle"@@ -129,6 +144,7 @@                                             , [(0, 2), (1, 3), (2, 4)]                                             , [(4, 0), (4, 1), (3, 2)] ]     , testCase "parse multioutsideclues" $ test_multioutside+    , testCase "parse edge grid" $ test_edge_grid     ]  -- this used to cause a rendering crash, though it's