Advertisement
Guest User

Wolf and hounds

a guest
Dec 5th, 2015
181
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. module Main where
  2.  
  3. import System.IO
  4. import System.Exit
  5. import Data.Binary
  6. import Data.List
  7. import Data.Ord
  8. import Control.Exception
  9.  
  10. main = menu
  11. -- Menu options
  12. data MainMenuOption = NewGame | Load | Exit | Unknown
  13.  
  14. menu = do
  15.     printMenu
  16.     choice <- getLine
  17.     let option = translate choice
  18.     case option of
  19.         NewGame -> do
  20.             play newGameState
  21.             menu
  22.         Load -> do
  23.             savedState <- try (load :: IO GameState) :: IO (Either IOException GameState)
  24.             case savedState of
  25.                 Left ex -> do
  26.                     putStrLn "Nie udało się załadować pliku!"
  27.                     menu
  28.                 Right gameState -> do
  29.                     play gameState
  30.                     menu
  31.         Exit -> return ()
  32.         Unknown -> do
  33.             printMenuError
  34.             menu
  35.  
  36. printMenu = do
  37.     putStrLn "Menu:"
  38.     putStrLn "1. Nowa gra"
  39.     putStrLn "2. Załaduj grę"
  40.     putStrLn "3. Wyjście\n"
  41.     putStr "> "
  42.     hFlush stdout
  43.  
  44. printMenuError = do
  45.     putStrLn "Nieprawidłowa opcja!\n"
  46.  
  47. translate :: String -> MainMenuOption
  48. translate "1" = NewGame
  49. translate "2" = Load
  50. translate "3" = Exit
  51. translate _ = Unknown
  52.  
  53. -- Data model
  54. data Point = Point Int Int deriving (Show, Eq)
  55. data Winner = Wolf | Hounds | Neither deriving (Show, Eq)
  56. data Turn = WolfTurn | HoundsTurn deriving (Show, Eq)
  57. data GameState = GameState Point [Point] Turn deriving (Show)
  58.  
  59. data PlayerChoice = ChoiceMove Point | ChoiceExit | ChoiceSave
  60.  
  61. -- Game
  62. newGameState :: GameState
  63. newGameState = GameState (Point 4 7) [(Point 1 0), (Point 3 0), (Point 5 0), (Point 7 0)] WolfTurn
  64.  
  65. play :: GameState -> IO ()
  66. play g@(GameState w (h:hs) turn)
  67.     | getWinner g == Wolf = do
  68.         printBoard g
  69.         putStrLn "Wygrałeś!\n"
  70.     | getWinner g == Hounds = do
  71.         printBoard g
  72.         putStrLn "Przegrałeś!\n"
  73.     | turn == WolfTurn = do
  74.         printBoard g
  75.         let moves = getWolfPossibleMoves g
  76.         move <- (askPlayerForMove moves)
  77.         case move of
  78.             ChoiceMove p    -> play (applyWolfMove g p)
  79.             ChoiceExit      -> return ()
  80.             ChoiceSave      -> do
  81.                 save g
  82.                 play g
  83.     | turn == HoundsTurn = do
  84.         let move = (getHoundsMove g (houndsMove g))
  85.         play move
  86.  
  87. getWinner :: GameState -> Winner
  88. getWinner (GameState (Point _ 0) _ _) = Wolf
  89. getWinner g
  90.     | (length (getWolfPossibleMoves g)) == 0 = Hounds
  91.     | otherwise = Neither
  92.  
  93. getWolfPossibleMoves :: GameState -> [Point]
  94. getWolfPossibleMoves g@(GameState w _ _) = [p | p <- (surroundingFields w), not (isOccupied g p)]
  95.  
  96. applyWolfMove :: GameState -> Point -> GameState
  97. applyWolfMove (GameState _ hs _) p = GameState p hs HoundsTurn
  98.  
  99. -- Printing game board
  100. printBoard :: GameState -> IO ()
  101. printBoard g = do
  102.     let board = getBoardString g
  103.     let framed = boardWithFrame board
  104.     putStrLn ("\n" ++ framed ++ "\n")
  105.  
  106. getBoardString :: GameState -> String
  107. getBoardString g = getBoardString' g g 0 0
  108.  
  109. getBoardString' :: GameState -> GameState -> Int -> Int -> String
  110. getBoardString' _ _ 8 7 = ""
  111. getBoardString' g_cur g_org 8 row = "\n" ++ (getBoardString' g_org g_org 0 (row+1))
  112. getBoardString' g_cur@(GameState w@(Point wx wy) ((Point hx hy):hs) turn) g_org col row
  113.     | col == wx && row == wy = "w" ++ next
  114.     | col == hx && row == hy = "o" ++ next
  115.     | otherwise = getBoardString' (GameState w hs turn) g_org col row
  116.     where
  117.         next = getBoardString' g_org g_org (col+1) row
  118. getBoardString' g_cur@(GameState _ [] _) g_org col row = " " ++ getBoardString' g_org g_org (col+1) row
  119.  
  120. boardWithFrame :: String -> String
  121. boardWithFrame board = "  12345678 \n +--------+\n" ++ (unlines newRows) ++ " +--------+\n  12345678 "
  122.     where
  123.         rows = indexedList (lines board)
  124.         newRows = [ (show (i+1)) ++ "|" ++ row ++ "|" ++ (show (i+1)) | (i,row) <- rows ]
  125.  
  126. -- Ask player for move
  127. askPlayerForMove :: [Point] -> IO PlayerChoice
  128. askPlayerForMove points = do
  129.     putStrLn "q. Przerwij"
  130.     putStrLn "s. Zapisz stan gry\n"
  131.     putStrLn "Wykonaj ruch:"
  132.     askPlayerForMove' points points 1
  133.  
  134. askPlayerForMove' :: [Point] -> [Point] -> Int -> IO PlayerChoice
  135. askPlayerForMove' [] p_org _ = do
  136.     putStrLn ""
  137.     putStr "> "
  138.     hFlush stdout
  139.     option <- getLine
  140.     if (isValidOption option (length p_org))
  141.         then do
  142.             let index = (read option) - 1          
  143.             return (ChoiceMove (p_org !! index))
  144.         else case option of
  145.             "q" -> return ChoiceExit
  146.             "s" -> return ChoiceSave
  147.             _   ->  do
  148.                         putStrLn "Nieprawidłowy wybór. Spróbuj ponownie:\n"
  149.                         askPlayerForMove p_org
  150.  
  151. askPlayerForMove' ((Point x y):ps) p_org idx = do
  152.     putStrLn ((show idx) ++ ". " ++ (show (x+1)) ++ " " ++ (show (y+1)))
  153.     askPlayerForMove' ps p_org (idx+1)
  154.  
  155.  
  156. -- Supporting functions
  157. indexedList :: [a] -> [(Int, a)]
  158. indexedList a = indexedList' 0 a
  159.  
  160. indexedList' :: Int -> [a] -> [(Int, a)]
  161. indexedList' i (x:xs) = [(i, x)] ++ (indexedList' (i+1) xs)
  162. indexedList' _ [] = []
  163.  
  164. surroundingFields :: Point -> [Point]
  165. surroundingFields (Point x y)
  166.     | x == 0 && y == 0  = [Point (x+1) (y+1)]
  167.     | x == 0 && y == 7  = [Point (x+1) (y-1)]
  168.     | x == 7 && y == 0  = [Point (x-1) (y+1)]
  169.     | x == 7 && y == 7  = [Point (x-1) (y-1)]
  170.     | x == 0            = [(Point (x+1) (y-1)), (Point (x+1) (y+1))]
  171.     | x == 7            = [(Point (x-1) (y-1)), (Point (x-1) (y+1))]
  172.     | y == 0            = [(Point (x-1) (y+1)), (Point (x+1) (y+1))]
  173.     | y == 7            = [(Point (x-1) (y-1)), (Point (x+1) (y-1))]
  174.     | otherwise         = [(Point (x-1) (y-1)), (Point (x-1) (y+1)), (Point (x+1) (y-1)), (Point (x+1) (y+1))]
  175.  
  176. isOccupied :: GameState -> Point -> Bool
  177. isOccupied (GameState w [] _) p = w == p
  178. isOccupied g@(GameState w (h:hs) t) p
  179.     | h == p = True
  180.     | otherwise = isOccupied (GameState w hs t) p
  181.  
  182. isInteger :: String -> Bool
  183. isInteger s = case reads s :: [(Integer, String)] of
  184.   [(_, "")] -> True
  185.   _         -> False
  186.  
  187. isValidOption :: String -> Int -> Bool
  188. isValidOption s max
  189.     | (isInteger s) = ((read s) <= max && (read s) >= 1)
  190.     | otherwise = False
  191.  
  192. -- Save
  193.  
  194. instance Binary Point where
  195.     put (Point x y) = do
  196.         put ((fromIntegral x) :: Word8)
  197.         put ((fromIntegral y) :: Word8)
  198.  
  199.     get = do
  200.         x <- get :: Get Word8
  201.         y <- get :: Get Word8
  202.         return (Point ((fromIntegral x) :: Int) ((fromIntegral y) :: Int))
  203.  
  204. instance Binary Turn where
  205.     put t = case t of
  206.         WolfTurn -> do
  207.             put (0 :: Word8)
  208.         HoundsTurn -> do
  209.             put (1 :: Word8)
  210.  
  211.     get = do
  212.         t <- get :: (Get Word8)
  213.         case t of
  214.             0 -> return WolfTurn
  215.             1 -> return HoundsTurn
  216.  
  217. instance Binary GameState where
  218.     put (GameState w hs t) = do
  219.         put w
  220.         put hs
  221.         put t
  222.  
  223.     get = do
  224.         w <- get :: Get Point
  225.         hs <- get :: Get [Point]
  226.         t <- get :: Get Turn
  227.         return (GameState w hs t)
  228.  
  229. save :: GameState -> IO ()
  230. save g = do
  231.     putStrLn "Podaj nazwe pliku:"
  232.     putStr "> "
  233.     hFlush stdout
  234.     name <- getLine
  235.     encodeFile name g
  236.  
  237. load :: IO GameState
  238. load = do
  239.     putStrLn "Podaj nazwe pliku:"
  240.     putStr "> "
  241.     hFlush stdout
  242.     name <- getLine
  243.     decodeFile name :: IO GameState
  244.  
  245. -- Hounds moves
  246.  
  247. getHoundsMove :: GameState -> GameState -> GameState
  248. getHoundsMove (GameState w hs _) (GameState _ newHs _) = (GameState w newHs WolfTurn)
  249.  
  250. houndsMove :: GameState -> GameState
  251. houndsMove g = getBestMove g
  252.  
  253. depth :: Int
  254. depth = 4
  255.  
  256. getBestMove :: GameState -> GameState
  257. getBestMove g = snd (maximumBy fstCmp rates)
  258.     where
  259.         possible = getPossibleMoves g
  260.         rates = [(getGameStateRate m depth, m) | m <- possible]
  261.  
  262. getPossibleMoves :: GameState -> [GameState]
  263. getPossibleMoves g@(GameState w hs WolfTurn) = [GameState loc hs HoundsTurn | loc <- locations]
  264.     where
  265.         locations = [p | p <- (surroundingFields w), not (isOccupied g p)]
  266. getPossibleMoves g@(GameState w hs HoundsTurn) = getHoundPossibleMoves g [] hs
  267. --                                      done    not done
  268. getHoundPossibleMoves :: GameState -> [Point] -> [Point] -> [GameState]
  269. getHoundPossibleMoves _ _ [] = []
  270. getHoundPossibleMoves g@(GameState w _ _) done (cur@(Point _ hy):ndone) = [(GameState w (done ++ [loc] ++ ndone) WolfTurn) | loc <- locations] ++ (getHoundPossibleMoves g (done ++ [cur]) ndone)
  271.     where locations = [p | p@(Point _ py) <- (surroundingFields cur), (not (isOccupied g p)) && py > hy]
  272.  
  273. getGameStateRate :: GameState -> Int -> Int
  274. getGameStateRate g 0 = getGameStateRate' g
  275. getGameStateRate g@(GameState w hs t) d
  276.     | length moves == 0 = getGameStateRate' g
  277.     | t == WolfTurn = minimum rates
  278.     | otherwise = maximum rates
  279.     where
  280.         moves = getPossibleMoves g
  281.         rates = [getGameStateRate m (d-1) | m <- moves]
  282.  
  283. fstCmp :: (Ord a) => (a,b) -> (a,b) -> Ordering
  284. fstCmp (a1, b1) (a2, b2)
  285.     | a1 > a2 = GT
  286.     | a1 < a2 = LT
  287.     | otherwise = EQ
  288.  
  289. getGameStateRate' :: GameState -> Int
  290. getGameStateRate' g@(GameState w hs t) =
  291.     case (getWinner g) of
  292.         Hounds  -> 100
  293.         Wolf    -> -100
  294.         Neither -> (getSurroundingHoundsCount w hs) * 20 - (wolfDistance w) * 10 - 10 * (fault1 w hs)
  295.  
  296. getSurroundingHoundsCount :: Point -> [Point] -> Int
  297. getSurroundingHoundsCount w hs = length [h | h <- hs, isNeighbour w h]
  298.  
  299. isNeighbour :: Point -> Point -> Bool
  300. isNeighbour (Point px py) (Point qx qy) = (abs (px - qx) == 1) && (abs (py - qy) == 1)
  301.  
  302. wolfDistance :: Point -> Int
  303. wolfDistance (Point px py) = 7 - py
  304.  
  305. fault1 :: Point -> [Point] -> Int
  306. fault1 _ [] = 0
  307. fault1 w@(Point _ wy) ((Point _ hy):hs) = (maximum [0, hy - wy]) + (fault1 w hs)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement