fork(3) download
  1. {-# OPTIONS_GHC -Wall #-}
  2. import Data.Array
  3. import Data.List
  4. import Data.Tree
  5. import Data.Maybe
  6.  
  7. input :: [String]
  8. input =
  9. [ " GYRR"
  10. , "RYYGYG"
  11. , "GYGYRR"
  12. , "RYGYRG"
  13. , "YGYRYG"
  14. , "GYRYRG"
  15. , "YGYRYR"
  16. , "YGYRYR"
  17. , "YRRGRG"
  18. , "RYGYGG"
  19. , "GRYGYR"
  20. , "GRYGYR"
  21. , "GRYGYR"
  22. ]
  23.  
  24. height :: Int
  25. height = length input
  26.  
  27. width :: Int
  28. width = length $ head input
  29.  
  30. type Board = Array Pos Mark
  31. type Mark = Char
  32. type Pos = (Int,Int) -- (y,x)
  33.  
  34. main :: IO ()
  35. main = mapM_ printBoard $ puyopuyo $ toBoard input
  36.  
  37. printBoard :: Board -> IO ()
  38. printBoard b = do
  39. mapM_ print $ fromBoard b
  40.  
  41. toBoard :: [String] -> Board
  42. toBoard [] = error "invalid parameter"
  43. toBoard ss = listArray ((0,0), (height-1,width-1)) $ concat ss
  44.  
  45. fromBoard :: Board -> [String]
  46. fromBoard = groupn width . map snd . assocs
  47.  
  48. positions :: Board -> [Pos]
  49. positions = (map fst) . assocs
  50.  
  51. -- | 次の状態を返す
  52. puyo :: Board -> Board
  53. puyo b = fall $ deleteMark b $ concat $ deletable b []
  54.  
  55. -- | (初期状態から平衡状態までの連続的な)状態のリストを返す
  56. puyopuyo :: Board -> [Board]
  57. puyopuyo b = if b == puyo b
  58. then []
  59. else (b : puyopuyo (puyo b))
  60.  
  61. -- | 4つ以上同色で連なっているものの座標を返す
  62. deletable :: Board -> [Pos] -> [[Pos]]
  63. deletable b passed = filter ((>=4).length) $ map flatten $ catMaybes $ deletable' b passed $ positions b
  64. where
  65. deletable' :: Board -> [Pos] -> [Pos] -> [Maybe (Tree Pos)]
  66. deletable' _ _ [] = []
  67. deletable' b' passed' (p':ps') = (connectTree b' passed' p') : (deletable' b' (p':passed') ps')
  68.  
  69. deleteMark :: Board -> [Pos] -> Board
  70. deleteMark board ps = board // [(p,' ')|p<-ps]
  71.  
  72. -- | 落下(' 'を下に詰める)した状態を返す
  73. fall :: Board -> Board
  74. fall = toBoard . transpose . paddingFront width " " . map (paddingFrontSpace height . deleteSpace) . transpose . fromBoard
  75. where
  76. deleteSpace = filter (/=' ')
  77.  
  78. -- | リストを定数個ごとに分割する
  79. groupn :: Int -> [a] -> [[a]]
  80. groupn _ [] = []
  81. groupn n xs =
  82. let (xs1, xs2) = splitAt n xs
  83. in xs1 : groupn n xs2
  84.  
  85. -- | 文字列の先頭に" "を詰めて指定文字数のの文字列を返す
  86. paddingFrontSpace :: Int -> String -> String
  87. paddingFrontSpace n = paddingFront n ' '
  88.  
  89. -- | リストの先頭に指定した要素を詰めて、指定の数の要素数のリストを返す
  90. paddingFront :: Int -> a ->[a] -> [a]
  91. paddingFront n pad = reverse . take n . (++ (cycle [pad])) . reverse
  92.  
  93. -- | となり合った座標を返す
  94. neigbors :: Pos -> [Pos]
  95. neigbors (y,x) = [(y',x')|(x',y') <- [(x+1,y),(x-1,y),(x,y+1),(x,y-1)], 0 <= x', x' < width, 0 <= y', y' < height]
  96.  
  97. -- | 指定した座標のとなりで同色の座標リストを返す
  98. connects :: Board -> Pos -> [Pos]
  99. connects b p = (sameColors b p) `intersect` (neigbors p)
  100.  
  101. sameColors :: Board -> Pos -> [Pos]
  102. sameColors b p = map fst $ filter (\(_,m) -> (m /= ' ') && (m == (b!p))) $ assocs b
  103.  
  104. -- | 繋がったマークのPosリストをツリーにして返す(一度通ったところは除外する)
  105. -- >>> connectTree a [] (1,1)
  106. -- Just (Node {rootLabel = (1,1), subForest = [Node {rootLabel = (1,2), subForest = []},Node {rootLabel = (2,1), subForest = [Node {rootLabel = (3,1), subForest = []}]}]})
  107. connectTree :: Board -> [Pos] -> Pos -> Maybe (Tree Pos)
  108. connectTree b passed p = if p `elem` passed
  109. then Nothing
  110. else Just $ Node p $ subTs $ connects b p
  111. where
  112. subTs :: [Pos] -> [Tree Pos]
  113. subTs = catMaybes . map (connectTree b (p:passed))
  114.  
Success #stdin #stdout 0.02s 6292KB
stdin
Standard input is empty
stdout
"  GYRR"
"RYYGYG"
"GYGYRR"
"RYGYRG"
"YGYRYG"
"GYRYRG"
"YGYRYR"
"YGYRYR"
"YRRGRG"
"RYGYGG"
"GRYGYR"
"GRYGYR"
"GRYGYR"

"   YRR"
"R GGYG"
"G GYRR"
"R GYRG"
"YGYRYG"
"GYRYRG"
"YGYRYR"
"YGYRYR"
"YRRGRG"
"RYGYGG"
"GRYGYR"
"GRYGYR"
"GRYGYR"

"    RR"
"R  YYG"
"G  YRR"
"R  YRG"
"YGYRYG"
"GYRYRG"
"YGYRYR"
"YGYRYR"
"YRRGRG"
"RYGYGG"
"GRYGYR"
"GRYGYR"
"GRYGYR"

"     R"
"R   RG"
"G   RR"
"R   RG"
"YGYRYG"
"GYRYRG"
"YGYRYR"
"YGYRYR"
"YRRGRG"
"RYGYGG"
"GRYGYR"
"GRYGYR"
"GRYGYR"

"      "
"R    R"
"G    G"
"R    G"
"YGYRYG"
"GYRYRG"
"YGYRYR"
"YGYRYR"
"YRRGRG"
"RYGYGG"
"GRYGYR"
"GRYGYR"
"GRYGYR"

"      "
"R     "
"G     "
"R     "
"YGYRY "
"GYRYRR"
"YGYRYR"
"YGYRYR"
"YRRGRG"
"RYGYGG"
"GRYGYR"
"GRYGYR"
"GRYGYR"

"      "
"R     "
"G     "
"R     "
"YGYR  "
"GYRYY "
"YGYRY "
"YGYRY "
"YRRGRG"
"RYGYGG"
"GRYGYR"
"GRYGYR"
"GRYGYR"

"      "
"R     "
"G     "
"R     "
"YGY   "
"GYRR  "
"YGYR  "
"YGYR  "
"YRRGRG"
"RYGYGG"
"GRYGYR"
"GRYGYR"
"GRYGYR"

"      "
"R     "
"G     "
"R     "
"YG    "
"GYY   "
"YGY   "
"YGY   "
"YRRGRG"
"RYGYGG"
"GRYGYR"
"GRYGYR"
"GRYGYR"

"      "
"R     "
"G     "
"R     "
"Y     "
"GG    "
"YG    "
"YG    "
"YRRGRG"
"RYGYGG"
"GRYGYR"
"GRYGYR"
"GRYGYR"

"      "
"      "
"R     "
"G     "
"R     "
"Y     "
"Y     "
"Y     "
"YRRGRG"
"RYGYGG"
"GRYGYR"
"GRYGYR"
"GRYGYR"

"      "
"      "
"      "
"      "
"      "
"      "
"R     "
"G     "
"RRRGRG"
"RYGYGG"
"GRYGYR"
"GRYGYR"
"GRYGYR"

"      "
"      "
"      "
"      "
"      "
"      "
"      "
"      "
"R  GRG"
"GYGYGG"
"GRYGYR"
"GRYGYR"
"GRYGYR"

"      "
"      "
"      "
"      "
"      "
"      "
"      "
"      "
"   GRG"
" YGYGG"
" RYGYR"
" RYGYR"
"RRYGYR"

"      "
"      "
"      "
"      "
"      "
"      "
"      "
"      "
"   GRG"
"  GYGG"
"  YGYR"
"  YGYR"
" YYGYR"

"      "
"      "
"      "
"      "
"      "
"      "
"      "
"      "
"   GRG"
"   YGG"
"   GYR"
"   GYR"
"  GGYR"

"      "
"      "
"      "
"      "
"      "
"      "
"      "
"      "
"    RG"
"    GG"
"    YR"
"   GYR"
"   YYR"

"      "
"      "
"      "
"      "
"      "
"      "
"      "
"      "
"     G"
"     G"
"     R"
"    RR"
"   GGR"

"      "
"      "
"      "
"      "
"      "
"      "
"      "
"      "
"      "
"      "
"      "
"     G"
"   GGG"