import System.Random import Control.Monad import Data.List import Data.Ord import Data.Array showNum :: (Num a, Show a) => Int -> a -> String showNum w = until ((>w-1).length) (' ':) . show replace :: Int -> a -> [a] -> [a] replace n c ls = take (n-1) ls ++ [c] ++ drop n ls target = "METHINKS IT IS LIKE A WEASEL" pfit = length target mutateRate = 20 popsize = 100 charSet = listArray (0,26) $ ' ': ['A'..'Z'] :: Array Int Char fitness = length . filter id . zipWith (==) target printRes i g = putStrLn $ "gen:" ++ showNum 4 i ++ " " ++ "fitn:" ++ showNum 4 (round $ 100 * fromIntegral s / fromIntegral pfit ) ++ "% " ++ show g where s = fitness g mutate :: [Char] -> Int -> IO [Char] mutate g mr = do let r = length g chances <- replicateM r $ randomRIO (1,mr) let pos = elemIndices 1 chances chrs <- replicateM (length pos) $ randomRIO (bounds charSet) let nchrs = map (charSet!) chrs return $ foldl (\ng (p,c) -> replace (p+1) c ng) g (zip pos nchrs) evolve :: [Char] -> Int -> Int -> IO () evolve parent gen mr = do when ((gen-1) `mod` 20 == 0) $ printRes (gen-1) parent children <- replicateM popsize (mutate parent mr) let child = maximumBy (comparing fitness) (parent:children) if fitness child == pfit then printRes gen child else evolve child (succ gen) mr main = do let r = length target genes <- replicateM r $ randomRIO (bounds charSet) let parent = map (charSet!) genes evolve parent 1 mutateRate