Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
147 changes: 122 additions & 25 deletions src/Chapter3.hs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤑 💰

, bookYear :: Int
}
{- |
=⚔️= Task 2

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧀 🍨 🧊
These are new! Would need to add Frühstück into my schedule 😄

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's the second German breakfast 🥳


{- |
=⚔️= Task 4
Expand All @@ -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
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The task tells that the castle should have a name. In this case, it can be a String.
Sorry, if it wasn't clear before. 😞 We improved this task wording in the latest version to clarify this moment.

Could you guess, what functions would need patching in case of the type modifications? 🙂

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had read: Optional castle with a name, sorry. I'll try

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No worries, it's our bad that the wording wasn't clear!


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
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice combination of the standard functions 👍🏼

then city { cityCastle = CastleWithWalls }
else city
_ -> city
{-
=🛡= Newtypes

Expand Down Expand Up @@ -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 }
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice work on newtypes! 🏅 Newtypes are one very important feature in Haskell 👍


{- |
=🛡= Polymorphic data types
Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This would show the shortest distance to Friday, however, time doesn't work like this.
For example. if it is Saturday, it would tell you that it is -1 day to Friday, however, it is 6 days to go 🥳

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I changed the regular order of days because of this, but I am aware that this is a cheat 😰

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, this one way to do it, but I agree, that this looks like a cheat 😄

You can apply the knowledge that we know exactly that there are 7 days in a week. So we can just calculate everything by mod 7!

Let's look how it would work:

ghci> mod (5) 7
5
ghci> mod (-1) 7
6

Looks like just what we need!

{-
=💣= Task 9*

Expand Down