5
\$\begingroup\$

Basically, there is an election on 3 regions where either candidate needs to win 2 in order to win the election. Idea is to simulate 10000 elections to see which candidate wins. I think my solution works but I am not happy with the huge list of if statements and wondering of if there is a better way for this.

# Assignment simulate elections page 257

# 2 Candidates A and B

# Candidate A has following odds:
# 87% change of winning in region 1
# 65% changes of winning in region 2
# 17% changes of winning in region 3

from random import random

candidate_a_won = 0
candidate_b_won = 0

for i in range(0, 10000):
    result = random()
    candidate_a = 0
    candidate_b = 0
    if result + .87 >= 1:
        candidate_a += 1
    else:
        candidate_b += 1
    if result + .65 >= 1:
        candidate_a += 1
    else:
        candidate_b += 1
    if result + .17 >= 1:
        candidate_a += 1
    else:
        candidate_b += 1
    if candidate_a > candidate_b:
        candidate_a_won += 1
    else:
        candidate_b_won += 1

print('Candidate A won elections {} times, candidate B won elections {} times'.format(candidate_a_won, candidate_b_won))
\$\endgroup\$
  • 1
    \$\begingroup\$ Are the comments all that were given in "Assignment simulate elections page 257"? If not, then your question would benefit from the problem statement. \$\endgroup\$ – Peilonrayz Feb 3 '17 at 14:53
  • \$\begingroup\$ Do you want to see how many times a candidate has won in each region? Is the victory determined by the amount of regions won or by the total percentage among all regions? \$\endgroup\$ – ChatterOne Feb 3 '17 at 15:30
5
\$\begingroup\$
  • Your code has a problem. Candidate A can loose region 1, but win region 3. Where with your code they can only win region 3 if they win region 2 and 1. This is as they are independent, and so you should random in each check.

  • You want to move your chances outside the loop into an array.

  • You can simplify your ifs into one comprehension.

  • Candidate a wins if they have more than half the regions, you don't need to calculate the amount of regions candidate b wins.

And so you could change your code to the following:

from random import random

AMOUNT = 10000
region_chances = [87, 65, 17]
region_chances = [1 - n / 100 for n in region_chances]
regions = len(region_chances)
candidate_a_won = sum(
    sum(random() >= chance for chance in region_chances) * 2 > regions
    for _ in range(AMOUNT)
)
candidate_b_won = AMOUNT - candidate_a_won
print('Candidate A won elections {} times, candidate B won elections {} times'.format(candidate_a_won, candidate_b_won))

If you want to extend on the above then it'll be hard if you decide to have more than two candidates, or even amounts of states. But as this is a challenge, I don't think you need to worry about these situations.

\$\endgroup\$
  • \$\begingroup\$ Thanks I did not realize that I was tying the regions together. Yes events should be independent. \$\endgroup\$ – Kimmo Hintikka Feb 3 '17 at 15:45
  • 1
    \$\begingroup\$ @KimmoHintikka You may want to un-accept my answer, as it reduces the incentive for others to answer. :) \$\endgroup\$ – Peilonrayz Feb 3 '17 at 15:50
5
\$\begingroup\$

A slightly alternative approach is determining the chances for A to win beforehand, and then just do one election (not one per region).

The chances for A to win is the chance to win in region A and B, but not in region C; plus the chance of winning in region B and C but not A; ...; plus the chance to win in all three regions:

\$ AB(1-C) + A(1-B)C + (1-A)BC + ABC = AB + AC + BC - 2ABC \approx 0.63\$

with \$A = 0.87, B = 0.65, C = 0.17\$

With this it becomes a bit easier:

amount = 10000
a, b, c = 0.87, 0.65, 0.17
chance = a*b + a*c + b*c - 2*a*b*c
candidate_a_won = sum(random() < chance for _ in range(amount))
candidate_b_won = amount - candidate_a_won
print('Candidate A won elections {} times, candidate B won elections {} times'.format(candidate_a_won, candidate_b_won))

This is a bit faster, but not as easily extendable to \$N\$ regions. For this we would need to derive a more general formula.

\$\endgroup\$
5
\$\begingroup\$

Per Graipher's answer, I extended the chance of victory to accept an arbitrary number of regions and number of wins required.

from itertools import combinations
from operator import mul

def get_probability_of_victory(regs, required_wins):
    prob = 0.
    for wins in range(required_wins, len(regs) + 1):
        for comb in combinations(regs, wins):
            prob += reduce(mul, (regs[r] if r in comb else 1 - regs[r] for r in regs))
    return prob


regions = {'1': 0.87, '2': 0.65, '3': 0.17}
required_wins = 2

chance = get_probability_of_victory(regions, required_wins)
# continue with Graipher's code...
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.