# Python election challenge

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))

• Are the comments all that were given in "Assignment simulate elections page 257"? If not, then your question would benefit from the problem statement. – Peilonrayz Feb 3 '17 at 14:53
• 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? – ChatterOne Feb 3 '17 at 15:30

• 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.

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

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.

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...