diff --git a/src/Chapter3.hs b/src/Chapter3.hs index 27a742f6..3f68bdf9 100644 --- a/src/Chapter3.hs +++ b/src/Chapter3.hs @@ -343,7 +343,13 @@ Define the Book product data type. You can take inspiration from our description of a book, but you are not limited only by the book properties we described. Create your own book type of your dreams! -} - +data Book = NewBook + { bookTitle :: String + , bookAutor :: String + , bookPages :: Int + , bookPrice :: Int + , bookYear :: Int + } {- | =⚔️= Task 2 @@ -373,6 +379,23 @@ after the fight. The battle has the following possible outcomes: doesn't earn any money and keeps what they had before. -} +data Knight = NewKnight + { knightHealth :: Int + , knightAttack :: Int + , knightGold :: Int + } deriving (Show) + +data Monster = NewMonster + { monsterHealth :: Int + , monsterAttack :: Int + , monsterGold :: Int + } deriving (Show) + +fight :: Knight -> Monster -> Int +fight knight monster + | monsterHealth monster - knightAttack knight <= 0 = knightGold knight + monsterGold monster + | knightHealth knight - monsterAttack monster <= 0 = -1 + | otherwise = knightGold knight {- | =🛡= Sum types @@ -459,6 +482,7 @@ and provide more flexibility when working with data types. Create a simple enumeration for the meal types (e.g. breakfast). The one who comes up with the most number of names wins the challenge. Use your creativity! -} +data Meal = Breakfast | Frühstück | Brunch | Lunch | Dinner | Supper | Snack | OnlyWater {- | =⚔️= Task 4 @@ -479,7 +503,40 @@ After defining the city, implement the following functions: complicated task, walls can be built only if the city has a castle and at least 10 living people inside -} - +data City = City + { cityCastle :: Castle + , cityMain :: MainBuilding + , cityHouses :: [House] + } + +data Castle = None | OnlyCastle | CastleWithWalls + +data MainBuilding = Church | Library +data House = One | Two | Three | Four + +countPeople :: House -> Int +countPeople house = case house of + One -> 1 + Two -> 2 + Three -> 3 + Four -> 4 + +buildCastle :: City -> City +buildCastle city = case cityCastle city of + None -> city { cityCastle = OnlyCastle } + _ -> city + +buildHouse :: House -> City -> City +buildHouse house city = + city { cityHouses = house : cityHouses city } + +buildWalls :: City -> City +buildWalls city = case cityCastle city of + OnlyCastle -> + if sum (map countPeople (cityHouses city)) >= 10 + then city { cityCastle = CastleWithWalls } + else city + _ -> city {- =🛡= Newtypes @@ -560,37 +617,39 @@ introducing extra newtypes. 🕯 HINT: if you complete this task properly, you don't need to change the implementation of the "hitPlayer" function at all! -} + +newtype Health = Health Int +newtype Armor = Armor Int +newtype Attack = Attack Int +newtype Dexterity = Dexterity Int +newtype Strength = Strength Int +newtype Damage = Damage Int +newtype Defense = Defense Int + data Player = Player - { playerHealth :: Int - , playerArmor :: Int - , playerAttack :: Int - , playerDexterity :: Int - , playerStrength :: Int + { playerHealth :: Health + , playerArmor :: Armor + , playerAttack :: Attack + , playerDexterity :: Dexterity + , playerStrength :: Strength } -calculatePlayerDamage :: Int -> Int -> Int -calculatePlayerDamage attack strength = attack + strength +calculatePlayerDamage :: Attack -> Strength -> Damage +calculatePlayerDamage (Attack attack) (Strength strength) = Damage (attack + strength) -calculatePlayerDefense :: Int -> Int -> Int -calculatePlayerDefense armor dexterity = armor * dexterity +calculatePlayerDefense :: Armor -> Dexterity -> Defense +calculatePlayerDefense (Armor armor) (Dexterity dexterity) = Defense (armor * dexterity) -calculatePlayerHit :: Int -> Int -> Int -> Int -calculatePlayerHit damage defense health = health + defense - damage +calculatePlayerHit :: Damage -> Defense -> Health -> Health +calculatePlayerHit (Damage damage) (Defense defense) (Health health) = Health (health + defense - damage) -- The second player hits first player and the new first player is returned hitPlayer :: Player -> Player -> Player hitPlayer player1 player2 = - let damage = calculatePlayerDamage - (playerAttack player2) - (playerStrength player2) - defense = calculatePlayerDefense - (playerArmor player1) - (playerDexterity player1) - newHealth = calculatePlayerHit - damage - defense - (playerHealth player1) - in player1 { playerHealth = newHealth } + let damage = calculatePlayerDamage (playerAttack player2) (playerStrength player2) + defense = calculatePlayerDefense (playerArmor player1) (playerDexterity player1) + newHealth = calculatePlayerHit damage defense (playerHealth player1) + in player1 { playerHealth = newHealth } {- | =🛡= Polymorphic data types @@ -752,7 +811,15 @@ parametrise data types in places where values can be of any general type. 🕯 HINT: 'Maybe' that some standard types we mentioned above are useful for maybe-treasure ;) -} - +data TreasureChest x = TreasureChest + { treasureChestGold :: Int + , treasureChestLoot :: x + } + +data DragonLair treasure power = DragonLair + { dragonLairChest :: Maybe (TreasureChest treasure) + , dragonLairDragonPower :: power + } {- =🛡= Typeclasses @@ -907,9 +974,25 @@ Implement instances of "Append" for the following types: ✧ *(Challenge): "Maybe" where append is appending of values inside "Just" constructors -} + +newtype Gold = Gold Int + class Append a where append :: a -> a -> a +instance Append Gold where + append :: Gold -> Gold -> Gold + append (Gold x) (Gold y) = Gold (x + y) + +instance Append [a] where + append :: [a] -> [a] -> [a] + append = (++) + +instance Append a => Append (Maybe a) where + append :: Maybe a -> Maybe a -> Maybe a + append Nothing mx = mx + append mx Nothing = mx + append (Just x) (Just y) = Just (append x y) {- =🛡= Standard Typeclasses and Deriving @@ -970,7 +1053,21 @@ implement the following functions: 🕯 HINT: to implement this task, derive some standard typeclasses -} +data Weekday = Sat | Sun | Mon | Tue | Wed | Thu | Fri deriving (Show, Eq, Enum, Bounded) + +isWeekend :: Weekday -> Bool +isWeekend weekday = case weekday of + Sat -> True + Sun -> True + _ -> False + +nextDay :: Weekday -> Weekday +nextDay weekday + | weekday == maxBound = minBound + | otherwise = succ weekday +daysToParty :: Weekday -> Int +daysToParty weekday = fromEnum Fri - fromEnum weekday {- =💣= Task 9*