Dom trzęsie się codziennie od kłótni nie między mną a mężem, ale przez tego zięcia. Ten człowiek, którego poślubiła moja córka, to istna personifikacja lenistwa i nieodpowiedzialności. Od ponad roku nie pracuje na stałe, łapiąc tylko dorywcze zlecenia, a res# hw5
## Due 2/19/2020 by 11:59pm
### **Problem 1 – 15 Points**
1. Use the `sample` function to write a function called `simulate_n_rolls` that takes as an input the number of rolls `n` and returns the results of `n` die rolls (you can choose the values of the die). For example, `simulate_n_rolls(5)` could return `1,6,2,6,3`.
2. Write a function called `run_simulations` that takes as input a list of integers and runs your `simulate_n_rolls` function on each one. It should return a list with the results. For example `run_simulations([5,3,4])` could return `[ (1,6,2,6,3), (5,2,1), (6,4,2,3) ]`.
### **Problem 2 – 20 Points**
1. Create a class called `Die`. The constructor (the `__init__` method) should take as input a list of values that the die can take. For example, if the list is `[1,2,3]`, then the die can take values 1, 2, or 3.
2. Add a method `roll` to your `Die` class that returns one of the values of the die with equal probability. For example, if the die is created by `Die([1,2,3])`, then `die.roll()` should return 1, 2, or 3 with equal probability.
3. Add a method `roll_n` to your `Die` class that takes as input an integer `n` and returns the results of `n` rolls. For example, if `die = Die([1,2,3])`, then `die.roll_n(4)` might return `[2,1,3,1]`.
### **Problem 3 – 15 Points**
1. Make a child class of `Die` called `WeightedDie`. The constructor of `WeightedDie` should take two lists as input: the first is the values of the die (just like `Die`), and the second is a list of weights (positive numbers that do not need to sum to 1). For example, `WeightedDie( [1,2,3], [2,6,2] )` would create a weighted die where 1 has weight 2, 2 has weight 6, and 3 has weight 2.
2. Override the `roll` function in `WeightedDie` so that it returns a value of the die with probability proportional to its weight. For example, in `WeightedDie( [1,2,3], [2,6,2] )`, the probability of rolling a 2 should be 6/(2+6+2) = 0.6, while the probabilities of 1 and 3 should each be 0.2.
### **Problem 4 – 20 Points**
1. Create a function called `roll_d20` that simulates a roll of a 20-sided die (i.e., returns an integer from 1 to 20 with equal probability).
2. Create a function called `attack_roll` that simulates a DnD attack roll. The function should return `True` if a simulated roll of a 20-sided die is *either* a 20 *or* greater than some input `threshold`. Otherwise, it should return `False`. For example, if the threshold is 15, then the function should return `True` if the die rolls 16,17,18,19, or 20.
3. Create a function called `test_attack_roll` that runs `attack_roll` `n` times and returns the fraction of times the function returns `True` for some given threshold. For example, for a threshold of 15, you would expect the function to return approximately 0.25 when `n` is large.
### **Problem 5 – 30 Points**
1. Create a function called `simulate_attack_round` that simulates one round of DnD attacks. The function should take as input:
– the attacker’s bonus to attack rolls (positive integer)
– the defender’s armor class (positive integer)
– the number of attacks (positive integer)
– the damage per attack (positive integer)
The function should proceed as follows: for each attack, the attacker rolls a d20 and adds their attack bonus. If the result is greater than or equal to the defender’s armor class, the attack hits. If the attack hits, the defender takes damage equal to the damage per attack. The function should return the total damage done to the defender.
For example, suppose the attacker has a +5 bonus, the defender has an armor class of 15, the attacker makes 2 attacks, and each attack does 6 damage. Then for each attack:
– The attacker rolls a d20 and adds 5.
– If the result is >= 15, the defender takes 6 damage.
If in the first attack the attacker rolls a 12, then the total is 12 + 5 = 17, which is >= 15, so the defender takes 6 damage. If in the second attack the attacker rolls a 7, then the total is 7 + 5 = 12, which is less than 15, so the defender takes 0 damage. The function would return 6.
2. Create a function called `run_simulations` that runs `simulate_attack_round` `n` times and returns the average damage dealt. For example, if the inputs are a +5 bonus, AC 15, 2 attacks, 6 damage, and `n = 1000`, you should get an average damage of around 5.4 (you can see why by computing the probability of hitting on one attack).
3. Create a function called `find_armor_class` that takes as input:
– the attacker’s bonus to attack rolls (positive integer)
– the number of attacks (positive integer)
– the damage per attack (positive integer)
– a target damage (positive integer)
The function should return the smallest armor class that would result in the average damage dealt being less than or equal to the target damage.
For example, if the attacker has a +5 bonus, makes 3 attacks, does 8 damage per attack, and the target damage is 10, then you should find that an armor class of 17 gives average damage of ~10.3, while an armor class of 18 gives average damage of ~8.2. Thus, the function should return 18.
*Hint: Use a while loop to test different armor classes until you find the right one.*



