Skip to content

Instantly share code, notes, and snippets.

@vituscze
Last active May 22, 2025 23:02
Show Gist options
  • Save vituscze/b9ae84d190db350cada42e6138020c90 to your computer and use it in GitHub Desktop.
Save vituscze/b9ae84d190db350cada42e6138020c90 to your computer and use it in GitHub Desktop.
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