Skip to content

Instantly share code, notes, and snippets.

@stuartlangridge
Created June 9, 2017 10:25
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save stuartlangridge/82295afd650cbafd8ab68202ef6f8c27 to your computer and use it in GitHub Desktop.
Save stuartlangridge/82295afd650cbafd8ab68202ef6f8c27 to your computer and use it in GitHub Desktop.
Work out possible coalitions for the UK 2017 general election
"""2017 general election
Given the vote totals, we have a hung parliament. Work out how coalitions
might be put together and display possibilities.
"""
import itertools
# vote totals correct as of about 10.30am Friday 9th June 2017
votes= {
'Conservative': 318, 'Sinn Fein': 7, 'DUP': 10,
'Sylvia Hermon': 1, 'Plaid Cymru': 4, 'Labour': 261, 'SNP': 35,
'Liberal Democrat': 12, 'Green Party': 1
}
abbrs = {
'Conservative': 'CON', 'Sinn Fein': 'SF', 'DUP': 'DUP',
'Sylvia Hermon': 'Hermon', 'Plaid Cymru': 'PC', 'Labour': 'LAB', 'SNP': 'SNP',
'Liberal Democrat': 'LD', 'Green Party': 'Green'
}
items = votes.items()
combs = {}
winners = {}
# There are 650 MPs, so 326 is a majority. But Sinn Fein don't take their seats (7, as above)
# and the speaker and two deputy speakers don't really count, so a practical "if you have this
# many then you look like a viable coalition government" is 320.
WINTOTAL = 320
for L in range(0, len(items)+1):
for subset in itertools.combinations(items, L):
parties = [x[0] for x in subset]
# OK, reject combinations that won't happen. First: don't display single parties in the list
if len(parties) == 1: continue
# There will be no Conservative + Labour coalition, obviously
if "Conservative" in parties and "Labour" in parties: continue
# The DUP explicitly said they don't like Labour
if "Democratic Unionist Party" in parties and "Labour" in parties: continue
# The LDs explicitly said they wouldn't go into coalitions with anyone
if "Liberal Democrat" in parties: continue
# Sinn Fein don't take their seats and will continue to not do so
if "Sinn Fein" in parties: continue
# No Green + CON: https://twitter.com/TheGreenParty/status/873023912430325765
if "Conservative" in parties and "Green Party" in parties: continue
parties.sort(key=lambda p:(votes[p],p), reverse=True)
name = set([abbrs[x] for x in parties])
namestr = ", ".join([abbrs[x] for x in parties])
lnamestr = ", ".join(parties)
if len(lnamestr) < 40: namestr = lnamestr
total = sum([x[1] for x in subset])
if total < 300: continue
combs[namestr] = total
if total >= WINTOTAL:
winners[namestr] = name
# Throw out all supersets; that is, if CON+DUP is enough to win, then obviously CON+DUP+PC
# is too, but don't count it; things on the winning list are the minimum possible. We don't
# throw out supersets of non-winning coalitions.
binit = set()
for ns, n in winners.items():
for checkns, checkn in winners.items():
if n < checkn:
binit.add(checkns)
for b in binit:
del combs[b]
ii = list(combs.items())
ii.sort(key=lambda c: c[1], reverse=True)
banner = False
# and print the output graph.
print()
for n, v in ii:
vc = v // 20
bar = "█" * vc
endbar = " " * (20 - vc)
if v < WINTOTAL and not banner:
print(" —————————— %s needed to look plausible? ——————————" % WINTOTAL)
banner = True
print (" %s%s%2d %s" % (bar, endbar, v, n))
print()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment