Reputation: 149
So I have a function fight,which takes two objects in the following manner:
fight :: (Combatant a, Combatant b) => (a, b) -> (a, b)
fight (fighter1, fighter2) =
let damageTo1 = ((attack fighter2) - (defense fighter1))
damageTo2 = ((attack fighter1) - (defense fighter2))
in (damage fighter1 damageTo1, damage fighter2 damageTo2)
The combatant class is as follows:
class Combatant a where
health :: a -> Int
attack :: a -> Int
defense :: a -> Int
level :: a -> Int
damage :: a -> Int -> a
I have two object types, Player, and Monster. The player has to fight monsters around him,so the monsters are actually in a list like [Monster1,Monster2,Monster3,Monster4...etc] and the player has to fight each single one.. so the function calls would go something like
fight(player,Monster1)
fight(player,Monster2)....etc..
However,I am not exactly sure how to make that happen ..I thought a function like map would be useful here but I'm not sure.. Ideas would be appreciated :)
Upvotes: 0
Views: 53
Reputation: 10228
You probably want a fold, a map, or 🌟both🌟. Given:
class Combatant a where
health :: a -> Int
attack :: a -> Int
defense :: a -> Int
damage :: a -> Int -> a
data Person = Person { personHP :: Int } deriving Show
data Monster = Monster { monsterHP :: Int } deriving Show
-- We will assume for time that your HP determines your attack.
instance Combatant Person where
health = personHP
attack = personHP
defense _ = 0
damage (Person hp) dmg = Person (hp - dmg)
instance Combatant Monster where
health = monsterHP
attack = monsterHP
defense _ = 0
damage (Monster hp) dmg = Monster (hp - dmg)
fight :: (Combatant a, Combatant b) => a -> b -> (a, b)
fight fighter1 fighter2 =
let damageTo1 = attack fighter2 - defense fighter1
damageTo2 = attack fighter1 - defense fighter2
in (damage fighter1 damageTo1, damage fighter2 damageTo2)
To do this, it's best to split up fight
so that it only returns the first combatant. As fight
is symmetrical, we can figure out what happens to the second combatant by reversing the order of our arguments. That looks like this
fight :: (Combatant a, Combatant b) => a -> b -> a
fight fighter1 fighter2 =
damage fighter1 (attack fighter2 - defense fighter1)
and this
λ> fight (Person 10) (Monster 5)
Person {personHP = 5}
λ> (flip fight) (Person 10) (Monster 5)
Monster {monsterHP = -5}
λ> fight (Monster 5) (Person 10)
Monster {monsterHP = -5}
Given a list of monsters and a single person:
λ> let person = Person 15
λ> let monsters = map Monster [1..4]
λ> monsters
[Monster {monsterHP = 1},Monster {monsterHP = 2},Monster {monsterHP = 3},Monster {monsterHP = 4}]
We're probably interested in asking two questions:
The second question is dispatched with a map, as @Aky mentioned.
λ> map (`fight` person) monsters
[Monster {monsterHP = -14},Monster {monsterHP = -13},Monster {monsterHP = -12},Monster {monsterHP = -11}]
Ouch. Whereas the answer to the first question might look like this:
λ> fight (fight (fight person (monsters !! 0)) (monsters !! 1)) (monsters !! 2) -- ... ugh, how tiresome ...
But this is what functional programmers call a fold left, which in Haskell goes by the foldl'
function (ignore the baroque apostrophe).
λ> foldl' _ person monsters
<interactive>:137:8:
Found hole ‘_’ with type: Person -> Monster -> Person
λ> foldl' fight person monsters
Person {personHP = 5}
Upvotes: 1