challenge METHINKS IT IS A WEASEL

ランダムな文字からMETHINKS IT IS A WEASELを作るプログラムを作れ。

簡単に流れを書いてみます。

1:ランダムな20文字を持つ文字列をもった300個作ります。

2:その文字列が"METHINKSITISAWEASEL"に近いものからソートします。

3:それぞれの文字列のなか1文字を別の文字に変化させたものを3つ用意します。

4:それを2:のソートをして上位300個残す。(900個あるうちで上位300個残すということです。)

5:以後3:と4:を繰り返す。

ランダムな文字変化は大文字だけでいいです。簡単にするために空白文字を外してあります。

METHINKS IT IS WEASELができたら終了。3と4の間でソートしたもので一番上位のものを毎回表示させると変化が楽しめます。:-)

Rickard Dawkinsがブラインドウォッチメイカー(現題:盲目の時計職人)の3章で書いていた有名なものです。さらに一般化してもらってもいいです。

参考

Posted feedbacks - Haskell

変異数:5。変異の仕方が文字列のどこか一文字をほかの文字と置き換える操作なので、スコアは正しい文字が正しい位置に何文字あるかで計算しています。

乱数生成がIOな関係上、やたらとIOな関数がいっぱい出てくるコードになっちゃいました。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
module Main where

import System.Random
import Data.Array.IArray
import Data.List
import Data.Function
import Data.Ord

goal    = "METHINKSITISAWEASEL"
score str = length $ filter (id) $ zipWith (==) str goal

updateRandom :: (Array Int Char) -> IO (Array Int Char)
updateRandom rg = do
    ch <- randChar
    i <- randPos
    return $ rg // [(i, ch)]

genRandStr :: IO (Array Int Char)
genRandStr = do
    str <- sequence $ replicate (length goal) (randChar)
    return $ listArray (0, length goal - 1) str

randChar= getStdRandom $ randomR ('A', 'Z')
randPos = getStdRandom $ randomR (0, (length goal) - 1)

sortIt :: [Array Int Char] -> [Array Int Char]
sortIt = sortBy (\x y -> inverse $ (comparing (score.elems) x y))
    where 
        inverse GT = LT
        inverse EQ = EQ
        inverse LT = GT

mutate :: [Array Int Char] -> IO [Array Int Char]
mutate strs = do
    strs' <- mapM (updateRandomN 5) strs
    return $ concat strs'
    where
        updateRandomN :: Int -> Array Int Char -> IO [Array Int Char]
        updateRandomN n str = mapM (updateRandom) $ replicate n str    

genMutation :: Int -> [Array Int Char] -> IO [Array Int Char]
genMutation i strs = do
    strs' <- mutate strs    
    return $ take 300 $ sortIt strs'

doCycle :: Int -> [Array Int Char] -> IO ()
doCycle i strs = do
    putStrLn $ (show i) ++ "th iteration:" ++ (elems $ head strs) ++ " : " 
        ++ (show $ score $ elems $ head strs)
    if (elems $ head strs) == goal then print "goal reached"
        else genMutation i strs >>= doCycle (i + 1)

main :: IO()
main = do
    strs <- sequence $ replicate 300 genRandStr
    doCycle 0 $ sortIt strs

Index

Feed

Other

Link

Pathtraq

loading...