fork download
  1. import Control.Applicative
  2. import Control.Monad
  3. import qualified Data.List as L
  4.  
  5. replace :: Eq a => a -> a -> [a] -> [a]
  6. replace from to = map f
  7. where f x | x == from = to
  8. | otherwise = x
  9.  
  10. blank :: Char
  11. blank = '□'
  12.  
  13. insertWord :: String -> Int -> Int -> [[String]]
  14. insertWord word i j = xs : [L.transpose xs]
  15. where
  16. xs = replicate j (replicate (length word + i) blank) ++ [replicate i blank ++ word]
  17.  
  18. blankMatrix :: (Int, Int) -> [String]
  19. blankMatrix (i, j) = [[blank | _ <- [1..j]] | _ <- [1..i]]
  20.  
  21. infixr 2 .||
  22. (.||) :: [String] -> [String] -> [String]
  23. xss1 .|| yss1 = maybe [] id $ f xss1 yss1
  24. where
  25. f :: [String] -> [String] -> Maybe [String]
  26. f (xs:xss) (ys:yss) = (:) <$> g xs ys <*> f xss yss
  27. f (xs:xss) _ = (:) <$> g xs [] <*> f xss []
  28. f _ (ys:yss) = (:) <$> g [] ys <*> f [] yss
  29. f _ _ = Just []
  30. g (x:xs) (y:ys) | x == blank = (y:) <$> g xs ys
  31. | y == blank = (x:) <$> g xs ys
  32. | x == y = (x:) <$> g xs ys
  33. | otherwise = Nothing
  34. g (x:xs) _ = (x:) <$> g xs []
  35. g _ (y:ys) = (y:) <$> g [] ys
  36. g _ _ = Just []
  37.  
  38. listup :: [String] -> [[String]]
  39. listup xs = foldM f [] xs
  40. where
  41. f a x = (a .||) <$> concat [insertWord x i j | i <- [0..len], j <- [0..len]]
  42. len = sum (map length xs) - (length xs - 1) - 1
  43.  
  44. isCrossWord :: [String] -> [String] -> Bool
  45. isCrossWord wordList matrix = L.sort wordList == L.sort pzWords && checkLen
  46. where
  47. pzWords = filter ((>1) . length) . concatMap (words . replace blank ' ') $ matrix ++ xst
  48. xst = L.transpose matrix
  49. checkLen = (sum $ map length wordList) - (length wordList - 1) == (sum . map sumc $ matrix)
  50. sumc xs = foldr (\x a -> if x == blank then a else a + 1) 0 xs
  51.  
  52. getWH :: [String] -> (Int, Int)
  53. getWH xss = (length xss, maximum $ map length xss)
  54.  
  55. findCrossWord :: [String] -> Maybe [String]
  56. findCrossWord wordList =
  57. liftA2 (.||) id (blankMatrix . getWH) <$> L.find (isCrossWord wordList) (listup wordList)
  58.  
  59. main :: IO ()
  60. main = do
  61. forM_ [ ["スイカ", "カイバ", "イヌ"], ["マンガ", "バター"] ] $
  62. putStrLn . maybe "not found." unlines . findCrossWord
  63.  
Success #stdin #stdout 0.02s 6276KB
stdin
Standard input is empty
stdout
スイカ□
□□イヌ
□□バ□

not found.