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 +12/−0
- README.md +58/−13
- data/fonts/gen-light.svg +419/−0
- puzzle-draw.cabal +66/−31
- src/Data/Puzzles/Compose.hs +8/−4
- src/Data/Puzzles/Elements.hs +9/−4
- src/Data/Puzzles/Grid.hs +68/−21
- src/Data/Puzzles/GridShape.hs +4/−4
- src/Data/Puzzles/PuzzleTypes.hs +9/−4
- src/Data/Puzzles/Pyramid.hs +6/−6
- src/Diagrams/Puzzles/CmdLine.hs +67/−0
- src/Diagrams/Puzzles/Draw.hs +7/−5
- src/Diagrams/Puzzles/Elements.hs +40/−31
- src/Diagrams/Puzzles/Grid.hs +81/−33
- src/Diagrams/Puzzles/Lib.hs +21/−13
- src/Diagrams/Puzzles/PuzzleGrids.hs +19/−22
- src/Diagrams/Puzzles/PuzzleTypes.hs +70/−43
- src/Diagrams/Puzzles/Pyramid.hs +16/−16
- src/Text/Puzzles/PuzzleTypes.hs +19/−12
- src/Text/Puzzles/Util.hs +109/−29
- src/tools/drawpuzzle.hs +145/−0
- tests/tests.hs +19/−3
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="
" 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="&" 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="<" 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=">" 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="—" horiz-adv-x="1020" +d="M958 230h-916v32h916v-32z" />+ <glyph glyph-name="trademark" unicode="™" 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="©" 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="®" 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="°" 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="Á" 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="Â" 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="Ä" 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="Å" 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="Ç" 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="È" 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="É" 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="Ê" 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="Ë" 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="Ì" horiz-adv-x="278" +d="M100 927l91 -143h-44l-127 143h80zM107 0v725h65v-725h-65z" />+ <glyph glyph-name="Iacute" unicode="Í" horiz-adv-x="278" +d="M258 927l-127 -143h-44l91 143h80zM107 0v725h65v-725h-65z" />+ <glyph glyph-name="Icircumflex" unicode="Î" horiz-adv-x="278" +d="M103 927h73l99 -145h-47l-89 106l-90 -106h-46zM107 0v725h65v-725h-65z" />+ <glyph glyph-name="Idieresis" unicode="Ï" horiz-adv-x="278" +d="M15 839v88h74v-88h-74zM189 839v88h74v-88h-74zM107 0v725h65v-725h-65z" />+ <glyph glyph-name="Ntilde" unicode="Ñ" 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="Ò" 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="Ó" 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="Ô" 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="Ö" 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="×" 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="Ø" 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="Ù" 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="Ú" 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="Û" 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="Ü" 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="à" +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="á" +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="â" +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="ã" +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="ä" +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="å" +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="ç" +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="è" 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="é" 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="ê" 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="ë" 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="ì" horiz-adv-x="222" +d="M72 707l91 -143h-44l-127 143h80zM81 0v502h60v-502h-60z" />+ <glyph glyph-name="iacute" unicode="í" horiz-adv-x="222" +d="M230 707l-127 -143h-44l91 143h80zM81 0v502h60v-502h-60z" />+ <glyph glyph-name="icircumflex" unicode="î" horiz-adv-x="222" +d="M75 707h73l99 -145h-47l-89 106l-90 -106h-46zM81 0v502h60v-502h-60z" />+ <glyph glyph-name="idieresis" unicode="ï" horiz-adv-x="222" +d="M-13 619v88h74v-88h-74zM161 619v88h74v-88h-74zM81 0v502h60v-502h-60z" />+ <glyph glyph-name="ntilde" unicode="ñ" 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="ò" 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="ó" 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="ô" 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="õ" 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="ö" 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="ù" 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="ú" 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="û" 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="ü" 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="ı" horiz-adv-x="222" +d="M81 0v502h60v-502h-60z" />+ <glyph glyph-name="fraction" unicode="⁄" horiz-adv-x="553" +d="M503 707l-405 -707h-48l407 707h46z" />+ <glyph glyph-name="quotedbl" unicode=""" 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="'" 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