import Control.Applicative
import Control.Monad.Random
-import Control.Monad(replicateM, liftM)
-import Data.List(sort)
+import Control.Monad(replicateM, liftM, foldM)
+import Data.List(sortBy)
------------------------------------------------------------
-- Die values
data Battlefield = Battlefield { attackers :: Army, defenders :: Army }
--- battle :: Battlefield -> Rand StdGen Battlefield
+newBattlefield :: Battlefield -> [DieValue] -> [DieValue] -> Battlefield
+newBattlefield battlefield rollA rollB =
+ let pairList = zip (sortBy (flip compare) rollA) (sortBy (flip compare) rollB)
+ in
+ foldr (\(a, d) acc -> if a > d then Battlefield (attackers acc) ((defenders acc) - 1)
+ else Battlefield ((attackers acc) - 1) (defenders acc)) battlefield pairList
+
+
+battle :: Battlefield -> Rand StdGen Battlefield
battle (Battlefield {attackers = a, defenders = d}) =
let rolla = replicateM (min (a - 1) 3) die
rolld = replicateM (min d 2) die
- zipped = liftA2 zip rolla rolld
in
-
+ liftA2 (newBattlefield (Battlefield a d)) rolla rolld
+
+-- exercise 3.
+endgame :: Battlefield -> Bool
+endgame (Battlefield {attackers=a, defenders=d}) = d == 0 || a < 2
+
+enemyDestroyed :: Battlefield -> Bool
+enemyDestroyed bf = endgame bf && (defenders bf) == 1
+
+invade :: Battlefield -> Rand StdGen Battlefield
+-- invade battlefield = foldM (\acc f -> f $ acc) battlefield (repeat battle)
+invade battlefield = battle battlefield >>= \bf ->
+ if (endgame bf) then return bf
+ else invade bf
+-- exercise 4
+successProb :: Battlefield -> Rand StdGen Double
+successProb battlefield = (pure (filter enemyDestroyed) <*> replicateM 1000 (invade battlefield))
+ >>= \xs -> return (fromIntegral (length xs) / 1000)