You are viewing a single comment's thread. Return to all comments →
import Data.Array import Data.List (sort) getWord :: String -> (Int, String) getWord ('-':cs) = (l+1, remainingCS) where (l, remainingCS) = getWord cs getWord (_:cs) = (1, cs) getWord "" = (1, "") wordsInLine :: Int -> String -> [(Int, Int)] wordsInLine _ "" = [] wordsInLine pos ('+':cs) = wordsInLine (pos+1) cs wordsInLine pos ('-':cs) = if firstWordLength > 1 then (pos, firstWordLength):otherWords else otherWords where (firstWordLength, remainingCS) = getWord cs otherWords = wordsInLine (pos+firstWordLength+1) remainingCS addY :: Int -> (Int, Int) -> (Int, Int, Int) addY y (x, l) = (x, y, l) wordsInLineWithY :: Int -> String -> [(Int, Int, Int)] wordsInLineWithY y line = map (addY y) (wordsInLine 0 line) addX :: Int -> (Int, Int) -> (Int, Int, Int) addX x (y, l) = (x, y, l) wordsInLineWithX :: Int -> String -> [(Int, Int, Int)] wordsInLineWithX x line = map (addX x) (wordsInLine 0 line) horizontalWords :: Int -> [String] -> [(Int, Int, Int)] horizontalWords _ [] = [] horizontalWords y (line:lines) = (wordsInLineWithY y line) ++ (horizontalWords (y+1) lines) verticalWords :: Int -> [String] -> [(Int, Int, Int)] verticalWords _ ([]:_) = [] verticalWords x linesIn = (wordsInLineWithX x line) ++ (verticalWords (x+1) lines) where line = map head linesIn lines = map tail linesIn letterLocations :: (Int,Int) -> Int -> Int -> Int -> [Int] letterLocations dir x y 0 = [] letterLocations dir@(dirX,dirY) x y l = (y*10+x):(letterLocations dir (x+dirX) (y+dirY) (l-1)) allLetterLocations :: (Int,Int) -> Int -> [(Int, Int, Int)] -> [(Int, (Int, Int))] allLetterLocations _ _ [] = [] allLetterLocations dir i ((x,y,l):ws) = wordLocsWithWordIndex ++ (allLetterLocations dir (i+1) ws) where wordLocs = zip (letterLocations dir x y l) [0..] f (arrayI, pos) = (arrayI, (i, pos)) wordLocsWithWordIndex = map f wordLocs mixInEmpty :: Int -> Int -> [(Int, (Int, Int))] -> [(Int, (Int, Int))] mixInEmpty i endI _ | i == endI = [] mixInEmpty i endI [] = (i,((-1),0)):(mixInEmpty (i+1) endI []) mixInEmpty i endI allE@((k,v):es) | k == i = (k,v):(mixInEmpty (i+1) endI es) | otherwise = (i,((-1),0)):(mixInEmpty (i+1) endI allE) intersectLookup :: [(Int, Int, Int)] -> Array Int (Int, Int) intersectLookup words = array (0,99) (mixInEmpty 0 100 (allLetterLocations (1,0) 0 words)) addToFront :: [a] -> Int -> a -> [a] addToFront l 0 _ = l addToFront l n e = e:(addToFront l (n-1) e) refsForWord :: Array Int (Int, Int) -> Int -> [Int] -> [(Int, Int, Int)] refsForWord _ _ [] = [] refsForWord lookup i (arrayI:vs) = if w == (-1) then rest else (i,w,c):rest where (w, c) = lookup!arrayI rest = refsForWord lookup (i+1) vs refs :: Array Int (Int, Int) -> [(Int, Int, Int)] -> [[(Int, Int, Int)]] refs _ [] = [] refs lookup ((x,y,l):vs) = lookupForThis:lookupForRest where locs = letterLocations (0,1) x y l lookupForThis = refsForWord lookup 0 locs lookupForRest = refs lookup vs getIntersects :: [(Int, Int, Int)] -> [(Int, Int, Int)] -> [[(Int, Int, Int)]] getIntersects hs vs = addToFront vrefs (length hs) [] where lookup = intersectLookup hs vrefs = refs lookup vs intersectsOK :: [(Int, Int, Int)] -> String -> [String] -> Bool intersectsOK [] _ _ = True intersectsOK ((charInThis,wordRef,charInWord):intersects) word resultSoFar = if resultSoFar!!wordRef!!charInWord == word!!charInThis then intersectsOK intersects word resultSoFar else False wordPossibilities :: Int -> [(Int, Int, Int)] -> [String] -> [String] -> [String] -> [([String], String)] wordPossibilities _ _ [] _ _ = [] wordPossibilities l intersects (word:wordsLeft) otherWordsLeft resultSoFar = if length(word) == l && intersectsOK intersects word resultSoFar then (otherWordsLeft++wordsLeft,word):otherPossibilities else otherPossibilities where otherPossibilities = wordPossibilities l intersects wordsLeft (word:otherWordsLeft) resultSoFar firstSolution :: [Int] -> [[(Int, Int, Int)]] -> [String] -> [([String], String)] -> [String] firstSolution _ _ _ [] = [] firstSolution ls intersects resultSoFar ((wordsLeft,word):ps) = if solution == [] then firstSolution ls intersects resultSoFar ps else solution where solution = solve' ls intersects wordsLeft (resultSoFar++[word]) solve' :: [Int] -> [[(Int, Int, Int)]] -> [String] -> [String] -> [String] solve' [] _ _ resultSoFar = resultSoFar solve' (l:ls) (intersect:intersects) words resultSoFar = firstSolution ls intersects resultSoFar ps where ps = wordPossibilities l intersect words [] resultSoFar solve :: [Int] -> [[(Int, Int, Int)]] -> [String] -> [String] solve wordLengths intersects words = solve' wordLengths intersects words [] renderChars :: [(Int,Int)] -> [(Int, Int, Int)] -> [String] -> [(Int, Char)] renderChars _ [] _ = [] renderChars (dir:dirs) ((x,y,l):spaces) (word:words) = forWord ++ rest where locs = letterLocations dir x y l forWord = zip locs word rest = renderChars dirs spaces words renderLine :: Int -> Int -> [(Int, Char)] -> String renderLine i endI cs | i == endI = "" renderLine i endI [] = '+':(renderLine (i+1) endI []) renderLine i endI allCS@((ci,c):cs) | ci < i = renderLine i endI cs | ci == i = c:(renderLine (i+1) endI cs) | otherwise = '+':(renderLine (i+1) endI allCS) renderLines :: Int -> [(Int, Char)] -> [String] renderLines 100 _ = [] renderLines startI cs = (renderLine startI endI cs):(renderLines endI cs) where endI = startI + 10 render :: [(Int,Int)] -> [(Int, Int, Int)] -> [String] -> [String] render dirs spaces words = renderLines 0 cs where cs = sort $ renderChars dirs spaces words wordsWhen :: (Char -> Bool) -> String -> [String] wordsWhen p s = case dropWhile p s of "" -> [] s' -> w : wordsWhen p s'' where (w, s'') = break p s' doit strIn = unlines resultLines where ls = lines strIn templateLines = take 10 ls [wordsToFitLine] = drop 10 ls wordsToFit = wordsWhen (==';') wordsToFitLine hs = horizontalWords 0 templateLines vs = verticalWords 0 templateLines intersects = getIntersects hs vs extractL (_,_,l) = l lengths = (map extractL hs) ++ (map extractL vs) solution = solve lengths intersects wordsToFit takeN n a = take n $ repeat a dirs = (takeN (length hs) (1,0)) ++ (takeN (length vs) (0,1)) resultLines = render dirs (hs++vs) solution main = interact doit
pls follow me and use this code with haskell
Seems like cookies are disabled on this browser, please enable them to open this website
Crosswords-101
You are viewing a single comment's thread. Return to all comments →
pls follow me and use this code with haskell