Last active
May 22, 2025 23:02
-
-
Save vituscze/b9ae84d190db350cada42e6138020c90 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module Main where | |
import Control.Monad | |
import Data.List | |
import Data.Maybe | |
modifyAt :: Int -> (a -> a) -> [a] -> [a] | |
modifyAt pos f l = ll ++ case lr of | |
[] -> [] | |
x:xs -> f x:xs | |
where | |
(ll, lr) = splitAt pos l | |
-- fun solution | |
modifyAt' :: Int -> (a -> a) -> [a] -> [a] | |
modifyAt' pos f = zipWith ($) (replicate pos id ++ f:repeat id) | |
type Sudoku = [[Int]] | |
boxSize :: Int | |
boxSize = 2 | |
sudokuSize :: Int | |
sudokuSize = boxSize * boxSize | |
getNextFree :: Sudoku -> Maybe (Int, Int) | |
getNextFree s = listToMaybe [(x, y) | (line, y) <- zip s [0 ..], (val, x) <- zip line [0 ..], val == 0] | |
setCell :: (Int, Int) -> Int -> Sudoku -> Sudoku | |
setCell (x, y) val = modifyAt y (modifyAt x (const val)) | |
chunks :: Int -> [a] -> [[a]] | |
chunks _ [] = [] | |
chunks n xs = take n xs:chunks n (drop n xs) | |
valid :: Sudoku -> Bool | |
valid sudoku = all validLine $ sudoku ++ transpose sudoku ++ boxes | |
where | |
validLine = (\l -> nub l == l) . filter (/= 0) | |
boxes = chunks boxSize sudoku >>= chunks sudokuSize . concat . transpose | |
solve :: Sudoku -> [Sudoku] | |
solve s = case getNextFree s of | |
Nothing -> [s] | |
Just (x, y) -> do | |
val <- [1 .. sudokuSize] | |
let s' = setCell (x, y) val s | |
guard (valid s') | |
solve s' | |
getSudoku :: IO Sudoku | |
getSudoku = replicateM sudokuSize (map (read . (: [])) <$> getLine) | |
main :: IO () | |
main = getSudoku >>= \s -> | |
case solve s of | |
[] -> putStrLn "no solution" | |
solved:_ -> mapM_ (putStrLn . concatMap show) solved | |
{- | |
104009356 | |
370608040 | |
950341200 | |
030000190 | |
497183000 | |
000070034 | |
000000020 | |
200000483 | |
703092015 | |
-} | |
restart LSP server -- configuration changed | |
cabal update | |
cabal init | |
cabal build | |
cabal run | |
-- alespon dva moduly | |
cabal haddock --haddock-executables | |
cabal repl | |
hie.yaml | |
cradle: | |
cabal: | |
component: "fractal" | |
hackage | |
hoogle | |
JuicyPixels, optparse-applicative | |
[[x :+ y | x <- [-2, -2 + 0.05 .. 2]] | y <- [2, 2 - 0.1 .. -2]] | |
defaultConfig = Config 300 300 (0 :+ 0) 0.01 255 "img.png" | |
cabal run . -- -s 0.000005 -l 1024 -- 1000 500 -1 0.287 | |
-- Mandelbrot.hs | |
{-# LANGUAGE RecordWildCards #-} | |
-- | Convergence testing. | |
module Mandelbrot | |
( converge | |
, pixelToComplex | |
) where | |
import Data.Complex | |
import Config | |
-- | Test whether a complex number belongs to the Mandelbrot set. | |
-- | |
-- The result is a number of iterations required for divergence to be | |
-- established, which happens when the number's absolute value is greater | |
-- than 2. | |
-- | |
-- >>> converge 100 (1 :+ 0) | |
-- 3 | |
-- | |
converge :: Int -- ^ Limit. | |
-> Complex Double -- ^ Initial point. | |
-> Int | |
converge lim c = go 0 0 | |
where | |
go steps z@(x :+ y) | |
| steps == lim = lim | |
| absSq <= 4 = go (steps + 1) (z * z + c) | |
| otherwise = steps | |
where | |
absSq = x * x + y * y | |
-- | Find a complex number corresponding to the given pixel coordinates. | |
-- | |
-- Use with 'converge'. | |
pixelToComplex :: Config -> Int -> Int -> Complex Double | |
pixelToComplex Config{..} x y = | |
(cx + xsteps * step) :+ (cy + ysteps * step) | |
where | |
cx :+ cy = center | |
xsteps = fromIntegral $ x - width `div` 2 | |
ysteps = fromIntegral $ y - height `div` 2 | |
-- Config.hs | |
-- | Image generation configuration. | |
module Config | |
( -- * The @Config@ type | |
Config(..) | |
-- * Option parsers | |
, parseConfig | |
) where | |
import Data.Complex | |
import Options.Applicative | |
data Config | |
= Config | |
{ width :: Int | |
, height :: Int | |
, center :: Complex Double | |
, step :: Double | |
, limit :: Int | |
, output :: String | |
} | |
parseConfig :: Parser Config | |
parseConfig = | |
Config <$> argument auto (metavar "WIDTH") | |
<*> argument auto (metavar "HEIGHT") | |
<*> parseCenter | |
<*> option auto (short 's' <> long "step" <> value 0.01) | |
<*> option auto (short 'l' <> long "limit" <> value 255) | |
<*> strOption (short 'o' <> long "output" <> value "img.png") | |
where | |
parseCenter = (:+) <$> argument auto (metavar "CENTERX") | |
<*> argument auto (metavar "CENTERY") | |
-- Main.hs | |
{-# LANGUAGE RecordWildCards #-} | |
-- | Main module. | |
module Main | |
( main | |
) where | |
import Codec.Picture | |
import Options.Applicative | |
import Config | |
import Mandelbrot | |
color :: Int -> Pixel8 | |
color = fromIntegral | |
opts :: ParserInfo Config | |
opts = info (parseConfig <* helper) (progDesc "Make a Mandelbrot set image.") | |
main :: IO () | |
main = do | |
c@Config{..} <- execParser opts | |
let picture = generateImage (\x y -> color . converge limit $ pixelToComplex c x y) width height | |
writePng output picture |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment