Guest User

Untitled

a guest
Oct 17th, 2018
88
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 3.63 KB | None | 0 0
  1.  
  2. import System.Random
  3.  
  4. import System.Console.GetOpt
  5. import System.Environment(getArgs, getProgName)
  6.  
  7. type Coord = (Int,Int)
  8. type Range = (Int,Int)
  9. type Area = (Coord,Coord) -- Upper-left and lower-right bounds.
  10.  
  11. data Tile = TFloor | TWall
  12. instance Show Tile where
  13. show TFloor = "."
  14. show TWall = "#"
  15.  
  16. type MRow = [Tile]
  17. type RMap = [MRow]
  18.  
  19. showMap :: RMap -> String
  20. showMap = unlines . map (>>= show)
  21.  
  22. makeMap :: Coord -> RMap
  23. makeMap (x,y) = replicate y (replicate x TWall)
  24.  
  25. splitGap :: Int -> Int -> [a] -> ([a],[a],[a])
  26. splitGap start size lst = (before, middle, after)
  27. where
  28. (before,rest) = splitAt start lst
  29. (middle,after) = splitAt (abs size) rest
  30.  
  31. digRow :: Range -> MRow -> MRow
  32. digRow (start,end) row =
  33. before ++ replicate size TFloor ++ after
  34. where
  35. size = end - start + 1
  36. (before,_,after) = splitGap start size row
  37.  
  38. digRoom :: RMap -> Area -> RMap
  39. digRoom rmap ((x,y),(u,v)) =
  40. ybefore ++ map (digRow (x,u)) rows ++ yend
  41. where
  42. (ybefore,rows,yend) = splitGap y (v-y+1) rmap
  43.  
  44. randomRoom :: (RandomGen r) => r -> Coord -> Area
  45. randomRoom gen (w,h) =
  46. ((x',y'),(u',v')) -- Note the reordering of xuyv to xyuv.
  47. where
  48. -- Here, x = n, so start with a random n.
  49. [x,y,u,v] = take 4 . map fst $ iterate (next.snd) (n,g)
  50. (n,g) = next gen
  51.  
  52. (x',u') = to_range x u w
  53. (y',v') = to_range y v h
  54. to_range a b max = (a',b')
  55. where
  56. minlen = 3
  57. a' = a `mod` (max-minlen-1) + 1
  58. brange = max - a' - minlen
  59. b' = (if brange > 0 then b `mod` brange else 0)
  60. + a' + minlen - 1
  61.  
  62. randomPoint :: RandomGen r => Area -> r -> Coord
  63. randomPoint ((x,y),(u,v)) gen =
  64. (x' `mod` (u-x+1) + x, y' `mod` (v-y+1) + y)
  65. where (x',g) = next gen
  66. (y',_) = next g
  67.  
  68. randomRooms :: RandomGen r => r -> Coord -> [Area]
  69. randomRooms gen dims = randomRoom g1 dims : randomRooms g2 dims
  70. where (g1,g2) = split gen
  71.  
  72. digHallway :: RMap -> Area -> RMap
  73. digHallway m ((x,y),(u,v)) = foldl digRoom m
  74. -- Dig from (x,y) to (u,y) to (u,v).
  75. [((u,min y v),(u,max y v)),((min x u,y),(max x u,y))]
  76.  
  77. digRandomHallways :: RandomGen r =>
  78. RMap -> r -> [Area] -> RMap
  79. digRandomHallways m gen rooms
  80. | length rooms < 2 = m
  81. | otherwise =
  82. digRandomHallways m' g4 (tail rooms)
  83. where
  84. (g1, gx) = split gen
  85. (g2, g3) = split gx
  86. ends = (randomPoint (rooms!!0) g1, randomPoint (tail rooms!!n) g2)
  87. m' = digHallway m ends
  88. (n',g4) = next g3
  89. n = n' `mod` (length $ tail rooms)
  90.  
  91. splatter :: RandomGen r => Int -> r -> RMap -> RMap
  92. -- Splatter n random rooms onto m.
  93. splatter n gen m =
  94. digRandomHallways (foldl digRoom m rooms) g2 rooms
  95. where
  96. (g1,g2) = split gen
  97. rooms = take n $ randomRooms g1 (length (m!!0),length m)
  98. center ((x,y),(u,v)) = ((x+u) `quot` 2, (y+v) `quot` 2)
  99.  
  100. data Options = Options {optRooms::Int,optDimensions::Coord}
  101.  
  102. defaults :: Options
  103. defaults = Options {optRooms=5,optDimensions=(80,60)}
  104.  
  105. options =
  106. [Option "n" ["rooms"]
  107. (ReqArg (\s op-> return op{optRooms=read s::Int}) "ROOMS")
  108. "Number of rooms to dig.",
  109. Option "d" ["dimensions"]
  110. (ReqArg (\s op-> case reads s :: [(Coord,String)] of
  111. ((dims,_):_) ->
  112. return op { optDimensions = dims }
  113. _ -> error "Dimensions must be in format (width,height)")
  114. "DIMENSIONS")
  115. "Dimensions of map."]
  116.  
  117. main = do
  118. -- Parse command line.
  119. argv <- getArgs
  120. let (actions,noops,msgs) = getOpt RequireOrder options argv
  121. ops <- foldl (>>=) (return defaults) actions
  122. let Options { optRooms=rooms, optDimensions=dimensions } = ops
  123.  
  124. gen <- newStdGen
  125. putStrLn . showMap . splatter rooms gen $ makeMap dimensions
Add Comment
Please, Sign In to add comment