Simulate Random Risk Battle
rollDieN doesn't look very random to me

*Risk&gt; map unDV $ rollDieN 100
[5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,6,6,6,6,6,6,6,6,6,
 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6]


This looks better:

*Risk&gt; map unDV $ evalRand (replicateM 100 die) (mkStdGen 123456)
[4,5,2,3,5,6,2,3,2,5,4,5,5,5,1,1,6,6,2,3,2,5,5,3,4,1,3,1,
 3,2,4,4,3,2,2,6,2,2,3,1,6,6,4,5,3,6,6,6,5,2,2,1,6,3,6,3,
 6,3,6,5,6,5,1,1,1,2,1,5,4,4,3,3,3,3,3,3,4,5,5,2,4,1,5,4,
 4,2,1,1,5,1,4,2,6,5,3,5,2,3,6,1]


Now we can write a function that will return the two army's dice rolls

rollDice n = replicateM n die

battleTest :: Battlefield -&gt; Rand StdGen ([Int], [Int])
battleTest battlefield = do
    attackerRolls &lt;- rollDice $ getLegalAttackers (attackers battlefield)
    defenderRolls &lt;- rollDice $ getLegalDefenders (defenders battlefield)
    return (map unDV attackerRolls, map unDV defenderRolls)


And check that our output looks sane

*Risk&gt; evalRand (battleTest (Battlefield 10 20)) (mkStdGen 12)
([6,3,2],[5,1])
*Risk&gt; evalRand (battleTest (Battlefield 10 20)) (mkStdGen 123456)
([4,5,2],[3,5])


Now assuming a function to update the battlefield based on dice rolls, we just change it to

battle :: Battlefield -&gt; Rand StdGen Battlefield
battle battlefield = do
    attackerRolls &lt;- rollDice $ getLegalAttackers (attackers battlefield)
    defenderRolls &lt;- rollDice $ getLegalDefenders (defenders battlefield)
    return $ nextBattlefield attackerRolls defenderRolls battlefield




There's also a problem with getLegalDefenders. The homework says


  The defending player may defend with up to two units (or only one if
  that is all they have).


So instead of


getLegalDefenders :: Army -&gt; Army
getLegalDefenders n 
  | n &gt;= 4    = 2
  | n == 3    = 1
  | otherwise = 0



It should look like

getLegalDefenders :: Army -&gt; Army
getLegalDefenders n 
  | n &gt;= 2    = 2
  | n == 1    = 1
  | otherwise = 0


Or

getLegalDefenders n = max 0 (min 2 n)