parent
							
								
									e3dc99342a
								
							
						
					
					
						commit
						f435c644c2
					
				
				 13 changed files with 99566 additions and 0 deletions
			
			
		| @ -0,0 +1,8 @@ | ||||
| # Chapter Exercises | ||||
| ## Hangman game logic | ||||
| see hangman/src/Main.hs | ||||
| 
 | ||||
| ## Modifying code | ||||
| 1. see src/ciphers.hs | ||||
| 2. see src/palindrome.hs | ||||
| 3. see src/person.hs | ||||
| @ -0,0 +1,8 @@ | ||||
| # Intermission: Check your understanding | ||||
| 1. `forever` and `when` | ||||
| 2. `Data.Bits` and `Database.Blacktip.Types` | ||||
| 3. The types used for the blacktip library | ||||
| 4.  | ||||
|     1. `Control.Concurrent.MVar`, `Filesystem.Path.CurrentOS` and `Control.Concurrent` | ||||
|     2. `import qualifed Filesystem as FS` | ||||
|     3. `import Control.Monad (forever, when)` | ||||
| @ -0,0 +1,30 @@ | ||||
| Copyright Author name here (c) 2017 | ||||
| 
 | ||||
| All rights reserved. | ||||
| 
 | ||||
| Redistribution and use in source and binary forms, with or without | ||||
| modification, are permitted provided that the following conditions are met: | ||||
| 
 | ||||
|     * Redistributions of source code must retain the above copyright | ||||
|       notice, this list of conditions and the following disclaimer. | ||||
| 
 | ||||
|     * Redistributions in binary form must reproduce the above | ||||
|       copyright notice, this list of conditions and the following | ||||
|       disclaimer in the documentation and/or other materials provided | ||||
|       with the distribution. | ||||
| 
 | ||||
|     * Neither the name of Author name here nor the names of other | ||||
|       contributors may be used to endorse or promote products derived | ||||
|       from this software without specific prior written permission. | ||||
| 
 | ||||
| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||||
| "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||||
| LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||||
| A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||||
| OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||||
| SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||||
| LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||||
| DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||||
| THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||||
| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||||
| OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
| @ -0,0 +1 @@ | ||||
| # hangman | ||||
| @ -0,0 +1,2 @@ | ||||
| import Distribution.Simple | ||||
| main = defaultMain | ||||
									
										
											File diff suppressed because it is too large
											Load Diff
										
									
								
							
						| @ -0,0 +1,23 @@ | ||||
| name:                hangman | ||||
| version:             0.1.0.0 | ||||
| -- synopsis: | ||||
| -- description: | ||||
| homepage:            https://github.com/githubuser/hangman#readme | ||||
| license:             BSD3 | ||||
| license-file:        LICENSE | ||||
| author:              Gaël Depreeuw | ||||
| maintainer:          example@example.com | ||||
| copyright:           2017 Gaël Depreeuw | ||||
| category:            Game | ||||
| build-type:          Simple | ||||
| cabal-version:       >=1.10 | ||||
| extra-source-files:  README.md, | ||||
|                      data/dict.txt | ||||
| 
 | ||||
| executable hangman | ||||
|   hs-source-dirs:      src | ||||
|   main-is:             Main.hs | ||||
|   default-language:    Haskell2010 | ||||
|   build-depends:       base >= 4.7 && < 5, | ||||
|                        random, | ||||
|                        split | ||||
| @ -0,0 +1,123 @@ | ||||
| module Main where | ||||
| 
 | ||||
| import Control.Monad (forever) | ||||
| import Data.Char (toLower, isAlpha) | ||||
| import Data.Maybe (isJust) | ||||
| import Data.List (intersperse) | ||||
| import System.Exit (exitSuccess) | ||||
| import System.Random (randomRIO) | ||||
| 
 | ||||
| newtype WordList = WordList [String] deriving (Eq, Show) | ||||
| 
 | ||||
| allWords :: IO WordList | ||||
| allWords = do | ||||
|   dict <- readFile "data/dict.txt" | ||||
|   return (WordList $ lines dict) | ||||
| 
 | ||||
| minWordLength :: Int | ||||
| minWordLength = 5 | ||||
| 
 | ||||
| maxWordLength :: Int | ||||
| maxWordLength = 9 | ||||
| 
 | ||||
| maxWrongGuesses :: Int | ||||
| maxWrongGuesses = 10 | ||||
| 
 | ||||
| gameWords :: IO WordList | ||||
| gameWords = do | ||||
|   WordList aw <- allWords | ||||
|   return $ WordList (filter gameLength aw) | ||||
|   where gameLength w =  | ||||
|           let l = length (w :: String) | ||||
|           in l >= minWordLength && l < maxWordLength | ||||
|              && all isAlpha w | ||||
| 
 | ||||
| randomWord :: WordList -> IO String | ||||
| randomWord (WordList wl) = do | ||||
|   randomIndex <- randomRIO (0, length wl - 1) | ||||
|   return $ wl !! randomIndex | ||||
| 
 | ||||
| randomWord' :: IO String | ||||
| randomWord' = gameWords >>= randomWord | ||||
| 
 | ||||
| data Puzzle = Puzzle String [Maybe Char] [Char] Int | ||||
| instance Show Puzzle where | ||||
|   show (Puzzle _ discovered guessed i) = | ||||
|     (intersperse ' ' $ fmap renderPuzzleChar discovered) | ||||
|     ++ " Guessed so far: " ++ guessed ++ "\n" | ||||
|     ++ "Wrong guesses so far: " ++ show i | ||||
| 
 | ||||
| freshPuzzle :: String -> Puzzle | ||||
| freshPuzzle s = Puzzle s l [] 0 | ||||
|     where l = fmap (const Nothing) s | ||||
| 
 | ||||
| charInWord :: Puzzle -> Char -> Bool | ||||
| charInWord (Puzzle s _ _ _) c = elem c s | ||||
| 
 | ||||
| alreadyGuessed :: Puzzle -> Char -> Bool | ||||
| alreadyGuessed (Puzzle _ _ s _) c = elem c s | ||||
| 
 | ||||
| renderPuzzleChar :: Maybe Char -> Char | ||||
| renderPuzzleChar Nothing = '_' | ||||
| renderPuzzleChar (Just c) = c | ||||
| 
 | ||||
| fillInCharacter :: Puzzle -> Char -> Puzzle | ||||
| fillInCharacter (Puzzle word filledInSoFar s i) c = | ||||
|   Puzzle word newFilledInSoFar (c:s) i | ||||
|   where newFilledInSoFar = zipWith (zipper c) word filledInSoFar | ||||
|         zipper guessed wordChar guessChar = | ||||
|           if wordChar == guessed | ||||
|           then Just wordChar | ||||
|           else guessChar | ||||
|   | ||||
| handleWrongGuess :: Puzzle -> Puzzle | ||||
| handleWrongGuess (Puzzle w f g i) = | ||||
|   Puzzle w f g (i+1) | ||||
| 
 | ||||
| handleGuess :: Puzzle -> Char -> IO Puzzle | ||||
| handleGuess puzzle guess = do | ||||
|   putStrLn $ "Your guess was: " ++ [guess] | ||||
|   case (charInWord puzzle guess, alreadyGuessed puzzle guess) of | ||||
|     (_, True) -> do | ||||
|       putStrLn "You already guessed that character, pick something else!" | ||||
|       return puzzle | ||||
|     (True, _) -> do | ||||
|       putStrLn "This character was in the word, filling in the word\ | ||||
|                \ accordingly" | ||||
|       return (fillInCharacter puzzle guess) | ||||
|     (False, _) -> do | ||||
|       putStrLn "This character wasn't in the word, try again." | ||||
|       return $ handleWrongGuess (fillInCharacter puzzle guess) | ||||
| 
 | ||||
| gameOver :: Puzzle -> Int -> IO () | ||||
| gameOver (Puzzle wordToGuess _ _ i) maxWrong = | ||||
|   if i >= maxWrong then | ||||
|     do putStrLn "You lose" | ||||
|        putStrLn $ "The word was: " ++ wordToGuess | ||||
|        exitSuccess | ||||
|   else return () | ||||
| 
 | ||||
| gameWin :: Puzzle -> IO () | ||||
| gameWin (Puzzle _ filledInSoFar _ _) = | ||||
|   if all isJust filledInSoFar then | ||||
|     do putStrLn "You win!" | ||||
|        exitSuccess | ||||
|   else return () | ||||
| 
 | ||||
| runGame :: Puzzle -> IO () | ||||
| runGame puzzle = forever $ do | ||||
|   gameOver puzzle maxWrongGuesses | ||||
|   gameWin puzzle | ||||
|   putStrLn $ "Current puzzle is: " ++ show puzzle | ||||
|   putStr "Guess a letter: " | ||||
|   guess <- getLine | ||||
|   case guess of | ||||
|     [c] -> handleGuess puzzle c >>= runGame | ||||
|     _   -> putStrLn "Your guess must be a single character" | ||||
| 
 | ||||
| 
 | ||||
| main :: IO () | ||||
| main = do | ||||
|   word <- randomWord' | ||||
|   let puzzle = freshPuzzle (fmap toLower word) | ||||
|   runGame puzzle | ||||
| @ -0,0 +1,66 @@ | ||||
| # This file was automatically generated by 'stack init' | ||||
| # | ||||
| # Some commonly used options have been documented as comments in this file. | ||||
| # For advanced use and comprehensive documentation of the format, please see: | ||||
| # https://docs.haskellstack.org/en/stable/yaml_configuration/ | ||||
| 
 | ||||
| # Resolver to choose a 'specific' stackage snapshot or a compiler version. | ||||
| # A snapshot resolver dictates the compiler version and the set of packages | ||||
| # to be used for project dependencies. For example: | ||||
| # | ||||
| # resolver: lts-3.5 | ||||
| # resolver: nightly-2015-09-21 | ||||
| # resolver: ghc-7.10.2 | ||||
| # resolver: ghcjs-0.1.0_ghc-7.10.2 | ||||
| # resolver: | ||||
| #  name: custom-snapshot | ||||
| #  location: "./custom-snapshot.yaml" | ||||
| resolver: lts-9.10 | ||||
| 
 | ||||
| # User packages to be built. | ||||
| # Various formats can be used as shown in the example below. | ||||
| # | ||||
| # packages: | ||||
| # - some-directory | ||||
| # - https://example.com/foo/bar/baz-0.0.2.tar.gz | ||||
| # - location: | ||||
| #    git: https://github.com/commercialhaskell/stack.git | ||||
| #    commit: e7b331f14bcffb8367cd58fbfc8b40ec7642100a | ||||
| # - location: https://github.com/commercialhaskell/stack/commit/e7b331f14bcffb8367cd58fbfc8b40ec7642100a | ||||
| #   extra-dep: true | ||||
| #  subdirs: | ||||
| #  - auto-update | ||||
| #  - wai | ||||
| # | ||||
| # A package marked 'extra-dep: true' will only be built if demanded by a | ||||
| # non-dependency (i.e. a user package), and its test suites and benchmarks | ||||
| # will not be run. This is useful for tweaking upstream packages. | ||||
| packages: | ||||
| - . | ||||
| # Dependency packages to be pulled from upstream that are not in the resolver | ||||
| # (e.g., acme-missiles-0.3) | ||||
| extra-deps: [] | ||||
| 
 | ||||
| # Override default flag values for local packages and extra-deps | ||||
| flags: {} | ||||
| 
 | ||||
| # Extra package databases containing global packages | ||||
| extra-package-dbs: [] | ||||
| 
 | ||||
| # Control whether we use the GHC we find on the path | ||||
| # system-ghc: true | ||||
| # | ||||
| # Require a specific version of stack, using version ranges | ||||
| # require-stack-version: -any # Default | ||||
| # require-stack-version: ">=1.5" | ||||
| # | ||||
| # Override the architecture used by stack, especially useful on Windows | ||||
| # arch: i386 | ||||
| # arch: x86_64 | ||||
| # | ||||
| # Extra directories used by stack for building | ||||
| # extra-include-dirs: [/path/to/dir] | ||||
| # extra-lib-dirs: [/path/to/dir] | ||||
| # | ||||
| # Allow a newer minor version of GHC than the snapshot specifies | ||||
| # compiler-check: newer-minor | ||||
| @ -0,0 +1 @@ | ||||
| Subproject commit dc97b6e0d15ae6d63c32f7b7fa35291270835552 | ||||
| @ -0,0 +1,82 @@ | ||||
| module Cipher where | ||||
| 
 | ||||
|     import Data.Char | ||||
|      | ||||
|     -- Chapter 9.12 | ||||
|     caesar :: String -> Int -> String | ||||
|     caesar [] _ = [] | ||||
|     caesar (x:xs) k | ||||
|         | isAlpha x = go x k ++ caesar xs k | ||||
|         | otherwise = caesar xs k | ||||
|         where go c key = [enc c (+) key] | ||||
| 
 | ||||
|     unCaesar :: String -> Int -> String | ||||
|     unCaesar [] _ = [] | ||||
|     unCaesar (x:xs) k | ||||
|         | isAlpha x = go x k ++ unCaesar xs k | ||||
|         | otherwise = caesar xs k | ||||
|         where go c key = [enc c (-) key] | ||||
|      | ||||
|     enc :: Char -> (Int -> Int -> Int) -> Int -> Char | ||||
|     enc c f k | ||||
|         | elem c ['a'..'z'] = chr (i 'a') | ||||
|         | elem c ['A'..'Z'] = chr (i 'A') | ||||
|         | otherwise = c | ||||
|         where i b  = (mod (ci b) r) + (ord b) | ||||
|               ci b = f ((ord c) - (ord b)) k | ||||
|               r = 26 | ||||
| 
 | ||||
|     alphaIndex :: Char -> Int | ||||
|     alphaIndex c | ||||
|         | elem c ['a'..'z'] = ord c - ord 'a' | ||||
|         | elem c ['A'..'Z'] = ord c - ord 'A' | ||||
|         | otherwise = 0 | ||||
| 
 | ||||
| 
 | ||||
|     shift :: Char -> Char -> Char | ||||
|     shift c k | ||||
|         | elem c ['a'..'z'] = go c k 'a' | ||||
|         | elem c ['A'..'Z'] = go c k 'A' | ||||
|         | otherwise = c | ||||
|         where go p key base = chr $ (mod rel r) + b | ||||
|                 where rel = alphaIndex p + alphaIndex key | ||||
|                       r = 26 | ||||
|                       b = ord base | ||||
| 
 | ||||
|     -- nice solution, but maps keyword to non-alpha characters | ||||
|     -- e.g. MEET_AT_DAWN  | ||||
|     --      ALLYALLYALLY | ||||
|     vigenere' :: [Char] -> [Char] -> [Char] | ||||
|     vigenere' xs ys = zipWith shift xs ((concat . repeat) ys) | ||||
| 
 | ||||
|     -- wrote own zipWith variant which maps only when isAlpha | ||||
|     vigenere :: [Char] -> [Char] -> [Char] | ||||
|     vigenere xs [] = xs -- necessary to avoid bottom | ||||
|     vigenere xs ys = myZipWith shift xs ys | ||||
|         where myZipWith _ [] _  = [] | ||||
|               myZipWith f s [] = myZipWith f s ys | ||||
|               myZipWith f (a:as) k@(b:bs) = | ||||
|                 if isAlpha a | ||||
|                 then f a b : myZipWith f as bs | ||||
|                 else     a : myZipWith f as k | ||||
| 
 | ||||
|     -- 1 | ||||
|     -- Not a lot of error checking, but just testing | ||||
|     -- reading the input | ||||
|     callCaesar :: IO () | ||||
|     callCaesar = do | ||||
|         putStrLn "Enter the plain text:" | ||||
|         s <- getLine | ||||
|         putStr "Enter the key (Char): " | ||||
|         c <- getChar | ||||
|         putStr "\n" | ||||
|         putStrLn $ caesar s $ alphaIndex c | ||||
| 
 | ||||
|     callVigenere :: IO () | ||||
|     callVigenere = do | ||||
|         putStrLn "Enter the plain text:" | ||||
|         s <- getLine | ||||
|         putStr "Enter the key (String): " | ||||
|         k <- getLine | ||||
|         putStr "\n" | ||||
|         putStrLn $ vigenere s k | ||||
| @ -0,0 +1,15 @@ | ||||
| module Palindrome where | ||||
| 
 | ||||
| import Control.Monad | ||||
| import Data.Char | ||||
| 
 | ||||
| palindrome :: IO () | ||||
| palindrome = forever $ do | ||||
|     line1 <- getLine | ||||
|     case (pal line1) of | ||||
|         True -> putStrLn "It's a palindrome!" | ||||
|         False -> putStrLn "Nope!" | ||||
|     where pal s =  | ||||
|            let s' = map toLower $ filter isAlpha s | ||||
|            in s' == reverse s' | ||||
|          | ||||
| @ -0,0 +1,36 @@ | ||||
| module Person where | ||||
| 
 | ||||
| type Name = String | ||||
| type Age = Integer | ||||
| 
 | ||||
| data Person = Person Name Age deriving Show | ||||
| 
 | ||||
| data PersonInvalid = | ||||
|     NameEmpty | ||||
|   | AgeTooLow | ||||
|   | PersonInvalidUnknown String | ||||
|   deriving (Show, Eq) | ||||
| 
 | ||||
| mkPerson :: Name -> Age -> Either PersonInvalid Person | ||||
| mkPerson name age | ||||
|     | name /= "" && age > 0 = Right $ Person name age | ||||
|     | name == "" = Left NameEmpty | ||||
|     | not (age > 0) = Left AgeTooLow | ||||
|     | otherwise = | ||||
|         Left $ PersonInvalidUnknown $ | ||||
|             "Name was: " ++ show name ++ | ||||
|             " Age was: " ++ show age | ||||
| 
 | ||||
| gimmePerson :: IO () | ||||
| gimmePerson = do | ||||
|     putStr "Provide a name: " | ||||
|     name <- getLine | ||||
|     putStr "Provide an age: " | ||||
|     age <- getLine | ||||
|     let p = mkPerson name ((read age) :: Integer) | ||||
|     case go p of | ||||
|         True  -> putStr "Yay! Succefully got a person: " | ||||
|         False -> putStrLn "Error: " | ||||
|     putStrLn $ show p | ||||
|     where go (Right _) = True | ||||
|           go (Left _)  = False | ||||
					Loading…
					
					
				
		Reference in new issue