Created
May 3, 2011 20:36
-
-
Save manicai/954175 to your computer and use it in GitHub Desktop.
Olympic Ticket Inferer
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
# | |
# Find prices of all possibilities of ticket allocations in the London | |
# 2012 Olympic lottery. | |
# | |
from itertools import chain, combinations | |
import re | |
import fileinput | |
def remove_pound(s): | |
"Strip the pound sign from a cost." | |
match = re.search('\d+\.\d{2}', s) | |
return float(match.group(0)) | |
class Session: | |
def __init__(self): | |
self.sport = '' | |
self.code = '' | |
self.datetime = '' | |
self.venue = '' | |
self.price_category = '' | |
self.quantity = '' | |
self.total_cost = '' | |
self.maximum_cost = '' | |
@property | |
def cost(self): | |
return remove_pound(self.total_cost) | |
@property | |
def max_cost(self): | |
return remove_pound(self.maximum_cost) | |
def __str__(self): | |
return "%s (%s)" % (self.sport, self.code) | |
def powerset(iterable): | |
"powerset([1,2,3]) --> () (1,) (2,) (3,) (1,2) (1,3) (2,3) (1,2,3)" | |
s = list(iterable) | |
return chain.from_iterable(combinations(s, r) for r in range(len(s)+1)) | |
Postage_Cost = 6 | |
def calculate_prices(options, overhead = Postage_Cost): | |
prices = {} | |
for tickets in powerset(options): | |
single_price = [t for t in tickets if t.max_cost == t.cost] | |
dual_price = [t for t in tickets if t not in single_price] | |
assert len(single_price) + len(dual_price) == len(tickets) | |
for high_priced in powerset(dual_price): | |
rest = [t for t in tickets if t not in high_priced] | |
cost = sum(session.max_cost for session in high_priced) | |
cost += sum(session.cost for session in rest) | |
if cost > 0: | |
cost += overhead | |
seats = list(chain([str(s) + '*' for s in high_priced], | |
[str(s) for s in rest])) | |
prices.setdefault(cost, []).append(seats) | |
return prices | |
Fields = { 'Session code' : 'code', | |
'Date/time' : 'datetime', | |
'Venue' : 'venue', | |
'Price Category' : 'price_category', | |
'Quantity' : 'quantity', | |
'Total cost' : 'total_cost', | |
'Total maximum cost' : 'maximum_cost' } | |
def parse_email(line_iter): | |
sessions = [] | |
current = None | |
for line in line_iter: | |
sport = re.match("\s+Sport: (.+)", line) | |
if sport: | |
if current: | |
sessions.append(current) | |
current = Session() | |
current.sport = sport.group(1) | |
elif current: | |
for field, attribute in Fields.items(): | |
regexp = '\s+%s: (.+)' % field | |
match = re.match(regexp, line) | |
if match: | |
setattr(current, attribute, match.group(1)) | |
break | |
if current: | |
sessions.append(current) | |
return sessions | |
if __name__ == '__main__': | |
sessions = parse_email(fileinput.input()) | |
possibilities = calculate_prices(sessions) | |
for price in sorted(possibilities): | |
for seats in possibilities[price]: | |
print '%10.2f : %s' % (price, ', '.join(seats)) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment