import urllib import random import time import pickle import zipfile import itertools from os import * def mysplitcsv(linetosplit): #custom line splitting code #like line.split(','), except it keeps text surrounded by quotes intact items = list() currentitem = '' currentnest = '' for c in linetosplit: if currentnest != '': if c == currentnest: currentnest = '' else: currentitem = currentitem + c else: if c == '"': currentnest = c elif c == ',': items.append(currentitem) currentitem = '' else: currentitem = currentitem + c items.append(currentitem) return items def translate_UTF8(line): #translate exotic UTF-8 characters - smart quotes and such - to plain ASCII utfstat = '' newline = '' for c in line: if c >= '\x80': if len(utfstat) < 3: utfstat = utfstat + c else: utfstat = utfstat[1] + utfstat[2] + c if UTF8translation.has_key(utfstat): newline = newline + UTF8translation[utfstat] utfstat = '' else: newline = newline + c utfstat = '' return newline def process_text_string(line): #line2 = line.lower() line2 = '' p = '' for c in line: if c.lower() != p.lower() or (c.isupper() and p.isupper()) or c.isdigit(): p = c line2 += p.lower() line2 = line2.replace('&','and') for c in ('#,:!?"\'.'): line2 = line2.replace(c,'') line2 = ''.join(line2.split()) line2 = line2.rstrip('s') return line2 #return 'foo' def mysplit(linetosplit): #custom line splitting code #like line.split(''), except it keeps text surrounded by quotes intact items = list() currentitem = '' currentnest = '' for c in linetosplit: if currentnest != '': if c == currentnest: currentnest = '' else: currentitem = currentitem + c else: if c == '"' or c == "'": currentnest = c elif len(c.strip()) == 0: if currentitem != '': items.append(currentitem) currentitem = '' else: currentitem = currentitem + c items.append(currentitem) return items def non_recursively_solve_schedule(event_info): #event_info #list of #tuple, #first element is priority #second element is list of #tuple #first element is list of #tuple #first element is event ID #second element is start time #third element is end time #fourth element is location #second element is total time penalty found_schedules = list() free_times = [] free_times.append((time.mktime(min(unique_entries[start_index])), time.mktime(max(unique_entries[end_index] )), None, None )) found_schedules.append((0.0,[],free_times)) #schedules: #list of found schedules so far #each of which is #(cost,(list of eventID added so far),(free times remaining)) while len(event_info) > 0: next_event_to_add = event_info[0] remaining_events = event_info[1:] priority = next_event_to_add[0] next_schedules = list() for prior_sched in found_schedules: #for each schedule found so far... score = prior_sched[0] schedule = prior_sched[1] for eventslot in next_event_to_add[1]: #print prior_sched,eventslot #for each possible slot for this event... events_toadd = list() remaining_free = list() free_times = prior_sched[2] free_slot = True penalty = eventslot[1] + priority for thiseventinfo in eventslot[0]: if free_slot != None: free_slot = None eventID,slot_start,slot_end,location = thiseventinfo time_penalty = penalty remaining_free = list() for timeslot in free_times: if timeslot[0] <= slot_start and timeslot[1] >= slot_end: free_slot = timeslot else: remaining_free.append(timeslot) if free_slot != None: #found a slot! #if float(unique_entries[cost_index][events_byID[eventID][cost_index]]) != 0.0: if True: start_time_spare = slot_start - free_slot[0] end_time_spare = free_slot[1] - slot_end start_time_location = free_slot[2] end_time_location = free_slot[3] #Penalize events which start or end too close to other events if start_time_spare < 900: if start_time_location != location: time_penalty -= 2.0 elif start_time_spare < 1800: if start_time_location != location: time_penalty -= 0.5 else: remaining_free.append((free_slot[0],slot_start,start_time_location,location)) if end_time_spare < 900: if end_time_location != location: time_penalty -= 2.0 elif end_time_spare < 1800: if end_time_location != location: time_penalty -= 0.5 else: remaining_free.append((slot_end,free_slot[1],location,end_time_location)) else: remaining_free.append(free_slot) events_toadd.append(eventID) free_times = remaining_free if free_slot != None: new_score = score + time_penalty new_schedule = schedule + events_toadd next_schedules.append((new_score,new_schedule,remaining_free)) if next_event_to_add[0] < 10: found_schedules += next_schedules else: found_schedules = next_schedules event_info = remaining_events found_schedules.sort(reverse = True) found_schedules = found_schedules [:10000] return found_schedules def solve_schedule(schedule): schedule.sort(key = lambda s:len(s[1]) * 1000 - s[0]) time_one = time.time() event_info = list() for event in schedule: priority = event[0] eventlist = event[1] events_with_times = list() for eventID in eventlist: eventstack = [[eventID]] if events_following.has_key(eventID): eventstack = eventstack + events_following[eventID] eventstack = map(list,list(itertools.product(*eventstack))) for eventIDlist in eventstack: thiseventinfo = list() time_penalty = 0.0 last_end_time = None for eventID in eventIDlist: anevent = events_byID[eventID] location = anevent[location_index] starttime = unique_entries[start_index][anevent[start_index]] endtime = unique_entries[end_index][anevent[end_index]] start_hour = int(time.strftime('%H',starttime)) end_hour = int(time.strftime('%H',endtime)) starttime = int(time.mktime(starttime)) endtime = int(time.mktime(endtime)) if eventID.startswith('TDA'): starttime = starttime - 900 #True Dungeon events need you to be there 15 minutes early if last_end_time != None and last_end_time > starttime: starttime = last_end_time last_end_time = endtime #Penalize late-night or early-morning events if start_hour > 23: time_penalty -= 2.0 if end_hour > 23: time_penalty -= 2.0 if start_hour < 20: time_penalty -= 1.0 if end_hour > 21: time_penalty -= 1.0 if end_hour > 16: time_penalty -= 0.1 if end_hour > 17: time_penalty -= 0.1 if start_hour < 8: time_penalty -= 0.4 if end_hour < 9: time_penalty -= 0. if start_hour < 5: time_penalty -= 2.0 if end_hour < 6: time_penalty -= 2.0 thiseventinfo.append((eventID,starttime,endtime,location)) events_with_times.append((thiseventinfo,time_penalty)) event_info.append((priority,events_with_times)) free_times = [] free_times.append((int(time.mktime(min(unique_entries[start_index]))), int(time.mktime(max(unique_entries[end_index] ))))) found_schedules = non_recursively_solve_schedule(event_info) time_four = time.time() found_schedules.sort(reverse = True) if len(found_schedules) > 0: return found_schedules else: return None def dosearch(search,eventpool): #print search foundevents = list() keyword = search[0] word = search[1] if word == '': return eventpool if keyword in ['any','all']: for eventID in eventpool: for i in [title_index,desc_index,long_desc_index,type_index,system_index,rules_index,company_index,gm_index]: event = events_byID[eventID] if word in filter(lambda c:c.islower() or c.isdigit() or c in word,unique_entries[i][event[i]].lower()): foundevents.append(eventID) if word.upper() in eventpool: foundevents.append(word.upper()) elif keyword in ['in','at']: for eventID in eventpool: for i in [location_index,room_index]: event = events_byID[eventID] if word in filter(lambda c:c.islower() or c.isdigit() or c in word,unique_entries[i][event[i]].lower()): foundevents.append(eventID) elif keyword in ['by']: for eventID in eventpool: for i in [company_index,gm_index]: event = events_byID[eventID] if word in filter(lambda c:c.islower() or c.isdigit() or c in word,unique_entries[i][event[i]].lower()): foundevents.append(eventID) elif keyword in ['type']: for eventID in eventpool: for i in [type_index]: event = events_byID[eventID] if unique_entries[i][event[i]].lower().startswith(word.lower()): #if word in filter(lambda c:c.islower() or c.isdigit() or word.startswith(c),unique_entries[i][event[i]].lower()): foundevents.append(eventID) elif keyword in ['on']: for eventID in eventpool: for i in [start_index,end_index]: event = events_byID[eventID] if time.strftime('%A',unique_entries[i][event[i]]).lower().startswith(word): foundevents.append(eventID) elif keyword in ['age']: for eventID in eventpool: for i in [age_index]: event = events_byID[eventID] if word.lower() in unique_entries[i][event[i]].lower(): foundevents.append(eventID) elif keyword in ['before']: thetime = None try: thetime = time.strptime(word,'%H') except ValueError: try: thetime = time.strptime(word,'%H:%M') except ValueError: try: thetime = time.strptime(word,'%I%p') except ValueError: try: thetime = time.strptime(word,'%I:%M%p') except ValueError: if word == 'noon': thetime = time.strptime('12','%H') if thetime != None: for eventID in eventpool: event = events_byID[eventID] if time.strptime(time.strftime('%H:%M',unique_entries[end_index][event[end_index]]),'%H:%M') < thetime: if time.strptime(time.strftime('%H:%M',unique_entries[start_index][event[start_index]]),'%H:%M') < thetime: foundevents.append(eventID) elif keyword in ['after']: thetime = None try: thetime = time.strptime(word,'%H') except ValueError: try: thetime = time.strptime(word,'%H:%M') except ValueError: try: thetime = time.strptime(word,'%I%p') except ValueError: try: thetime = time.strptime(word,'%I:%M%p') except ValueError: if word == 'noon': thetime = time.strptime('12','%H') if thetime != None: for eventID in eventpool: event = events_byID[eventID] if time.strptime(time.strftime('%H:%M',unique_entries[end_index][event[end_index]]),'%H:%M') > thetime: if time.strptime(time.strftime('%H:%M',unique_entries[start_index][event[start_index]]),'%H:%M') > thetime: foundevents.append(eventID) elif keyword in ['not']: not_found_events = dosearch(word,eventpool) foundevents = filter(lambda e:e not in not_found_events,eventpool) foundevents = list(set(foundevents)) foundevents.sort() return foundevents def find_events(wordlist): searches = list() search_keywords = ['any','all','on','in','at','by','before','after','type','not','age'] latest_keyword = '' #first_permitted_start = min(unique_entries[start_index]) #last_permitted_end = max(unique_entries[end_index]) next_not = False for word in wordlist: if word.lower() in search_keywords: if word.lower() == 'not': next_not = True else: latest_keyword = word.lower() else: if latest_keyword == '': if len(searches) > 0: last_search = searches.pop() if last_search[0] in ['any','all']: searches.append((last_search[0],last_search[1] + ' ' + word)) else: searches.append(last_search) searches.append(('any',word.lower())) latest_keyword = '' else: searches.append(('any',word.lower())) latest_keyword = '' else: if next_not: searches.append(('not',(latest_keyword,word.lower()))) else: searches.append((latest_keyword,word.lower())) latest_keyword = '' next_not = False eventpool = events_canprereg + events_generic #eventpool.sort(key = lambda eventID:unique_entries[start_index][events_byID[eventID][start_index]]) #uncomment this line to filter events with no slots left # eventpool = filter(lambda e:unique_entries[tickets_available_index][events_byID[e][tickets_available_index]] > 0,eventpool) #eventpool = events_byID.keys() for search in searches: #print search eventpool = dosearch(search,eventpool) #results = list() event_unique_keys = dict() #print 'Finding unique keys...' for eventID in eventpool: foo = ' '.join(map(str,map(lambda j:j in ident_indices and events_byID[eventID][j] or -1,range(number_of_colums)))) #foo = ' '.join(map(str,map(lambda j:events_byID[eventID][j],ident_indices))) event_unique_keys[eventID] = foo # print eventID,foo unique_keys = set(event_unique_keys.values()) events_by_unique_keys = dict() #eventIDs = events_byID.keys() for key in unique_keys: matching_events = filter(lambda k:event_unique_keys[k] == key,eventpool) #print matching_events newkey = map(lambda j:map(lambda eventID:events_byID[eventID][j],matching_events),range(number_of_colums)) #print foo #print foo newkey = map(lambda s:len(s) == 1 and list(s)[0] or -1,map(set,newkey)) newkey = ' '.join(map(str,newkey)) #print foo events_by_unique_keys[newkey] = matching_events #events_by_unique_keys.sort(key = lambda eventIDlist:unique_entries[start_index][events_byID[eventIDlist[0]][start_index]]) #print len(unique_keys),'unique event keys' return events_by_unique_keys def fix_location(location): location = location.replace(' Bllrm',' Ballroom') location = location.replace(' Blrm',' Ballroom') location = location.replace('Notra ','Notre ') location = location.replace('Penn ','Pennsylvania ') location = location.replace(' Stn',' Station') location = location.replace(' & ',' and ') location = location.replace(' SE',' Southeast') location = location.replace(' NE',' Southwest') location = location.replace(' SW',' Northeast') location = location.replace(' NW',' Northwest') location = location.replace(' Cntrl',' Central') location = location.replace('Exhibit Hl','Exhibit Hall') if location.endswith(' I'): location = location.replace(' I',' 1') elif location.endswith(' II'): location = location.replace(' II',' 2') elif location.endswith(' III'): location = location.replace(' III',' 3') elif location.endswith(' IV'): location = location.replace(' IV',' 4') elif location.endswith(' V'): location = location.replace(' V',' 5') if location == 'Family Fun Pavilion': location = 'Exhibit Hall: Family Fun Pavilion' return location def get_catalog(url): filenames = listdir('.') mydir = 'Catalogs' if not mydir in filenames: mkdir(mydir) #filenames = listdir(mydir) filenames = [] try: data = urllib.urlopen(url).read() #print data filefindstring = '
' event_file_locations = list() while data.find(filefindstring) > -1: data = data[data.find(filefindstring) + len(filefindstring):] item = data[data.find('')] fileloc = item.split('"')[1] #print fileloc if 'pmcompletecatalogs' in fileloc: event_file_locations.append(fileloc) #print print "Checking for new event catalog files..." found = False for csvfileloc in event_file_locations: #print csvfileloc print 'checking',csvfileloc url = 'http://community.gencon.com' + csvfileloc data = urllib.urlopen(url).read() #print data data = data[data.find('
'):] #print data data = data[data.find('')] zipfileloc = zipfileloc.split('"')[1] #print zipfileloc while data.find('') > -1: data = data[data.find(''):] propertyname = data[data.find('>')+1:data.find('')] #print propertyname, data = data[data.find(''):] propertyvalue = data[data.find('>')+1:data.find('')] #print propertyvalue data = data[data.find(''):] #data = url = 'http://community.gencon.com' + zipfileloc thisfilename = zipfileloc.split('/') print thisfilename thisfilename = thisfilename[len(thisfilename)-2] #print thisfilename #print filenames if not thisfilename + '.zip' in filenames: found = True print 'Found new event catalog:',thisfilename print 'Downloading it...' urllib.urlretrieve(url,mydir + '/' + thisfilename + '.zip') print 'Done. Decompressing and processing now.' data = None try: zf = zipfile.ZipFile(mydir + '/' + thisfilename + '.zip','r') files = zf.namelist() data = '' for filename in files: if filename.endswith ('.csv') and filename.find('/') == -1 and filename.find('..') == -1: zf.open(filename) data = zf.read(filename) zf.close() except: print 'Failed, unable to decompress.' data = None if data != None: lines = data.split('\n') lines = map(lambda x:x.rstrip('\r'),lines) splitlines = map(mysplitcsv,lines) column_titles = map(translate_UTF8,splitlines[0]) ll = len(column_titles) proclines = list() for line in splitlines[1:]: if len(line) == ll: fixedline = list() for i in range(len(line)): if 'room' in column_titles[i].lower(): fixedline.append(fix_location(translate_UTF8(line[i]))) else: fixedline.append(translate_UTF8(line[i])) proclines.append(fixedline) #proclines.append(map(translate_UTF8,line)) #print #print line #print fixedline columntypes = list() unique_entries_by_category = dict() #entries_as_shown_by_category = dict() unique_to_as_shown_map_by_category = dict() unique_to_as_shown_votes_by_category = dict() for i in range(len(column_titles)): lowtitle = column_titles[i].lower() columntype = 'TEXT' unique_contents = list() nonefailedbool = True anybool = False nonefailedfloat = True anynumeric = False nonefaileddate = True anydate = False for line in proclines: item = line[i].lower().strip(' ') if nonefailedfloat and item != '': try: foo = float(item) anynumeric = True except ValueError: nonefailedfloat = False if nonefaileddate and item != '': try: foo = time.strptime(item,'%m/%d/%Y %H:%M') anydate = True except ValueError: nonefaileddate = False if nonefailedbool and item != '': if (item == 'no' or item == 'yes' or item == 'true' or item == 'false'): anybool = True else: nonefailedbool = False if not item in unique_contents: unique_contents.append(item) if nonefailedbool and anybool: columntype = 'BOOL' elif nonefailedfloat and anynumeric: columntype = 'FLOAT' elif nonefaileddate and anydate: columntype = 'DATE' elif len(unique_contents) == len(proclines): columntype = 'ID' else: columntype = 'TEXT' columntypes.append(columntype) unique_entries_by_category[i] = list() #entries_as_shown_by_category[i] = list() unique_to_as_shown_map_by_category[i] = dict() unique_to_as_shown_votes_by_category[i] = dict() events_byID = dict() for line in proclines: #processed_event = list() #eventID = None for i in range(len(column_titles)): shown_item = line[i] if columntypes[i] == 'BOOL': item = shown_item.lower() if item == 'yes' or item == 'true': item = True else: item = False elif columntypes[i] == 'FLOAT': if shown_item != '': item = float(shown_item) else: item = 0.0 elif columntypes[i] == 'DATE': if shown_item != '': item = time.strptime(shown_item,'%m/%d/%Y %H:%M') else: item = 0 elif columntypes[i] == 'TEXT': item = process_text_string(shown_item) #if i == 4: # print item[:20]+'... = '+shown_item[:20]+'...' if columntypes[i] != 'ID': if not item in unique_entries_by_category[i]: unique_entries_by_category[i].append(item) #if i == 4: # print 'item not in unique_entries_by_category[i]' if not unique_to_as_shown_map_by_category[i].has_key(item): unique_to_as_shown_map_by_category[i][item] = list() unique_to_as_shown_votes_by_category[i][item] = dict() #if i == 4: # print 'not unique_to_as_shown_map_by_category[i].has_key(item)' if not shown_item in unique_to_as_shown_map_by_category[i][item]: unique_to_as_shown_map_by_category[i][item].append(shown_item) unique_to_as_shown_votes_by_category[i][item][shown_item] = 1 #if i == 4: # print 'not shown_item in unique_to_as_shown_map_by_category[i][item]' else: unique_to_as_shown_votes_by_category[i][item][shown_item] += 1 #if i == 4: # print 'unique_to_as_shown_votes_by_category[i][item][shown_item] =', unique_to_as_shown_votes_by_category[i][item][shown_item] for i in range(len(column_titles)): unique_entries_by_category[i].sort() for item in unique_to_as_shown_map_by_category[i].keys(): bestscore = 0 bestsub = '' for shown_item in unique_to_as_shown_map_by_category[i][item]: if unique_to_as_shown_votes_by_category[i][item][shown_item] > bestscore: bestsub = shown_item bestscore = unique_to_as_shown_votes_by_category[i][item][shown_item] #if i == 4: #if len(unique_to_as_shown_map_by_category[i][item]) > 1: #print item #for shown_item in unique_to_as_shown_map_by_category[i][item]: # print '\t',shown_item,unique_to_as_shown_votes_by_category[i][item][shown_item] #print #print bestsub #print unique_to_as_shown_map_by_category[i][item] = bestsub for line in proclines: processed_event = list() eventID = None for i in range(len(column_titles)): shown_item = line[i] if columntypes[i] == 'ID': eventID = shown_item elif columntypes[i] == 'BOOL': item = shown_item.lower() if item == 'yes' or item == 'true': item = True else: item = False elif columntypes[i] == 'FLOAT': if shown_item != '': item = float(shown_item) else: item = 0.0 elif columntypes[i] == 'DATE': if shown_item != '': item = time.strptime(shown_item,'%m/%d/%Y %H:%M') else: item = 0 elif columntypes[i] == 'TEXT': item = process_text_string(shown_item) if columntypes[i] != 'ID': #if i == 4: # print item,unique_entries_by_category[i].index(item) item = unique_entries_by_category[i].index(item) processed_event.append(item) if eventID != None: events_byID[eventID] = processed_event unique_entries = list() for i in range(len(column_titles)): if columntypes[i] == 'TEXT': mapped_unique = list() for item in unique_entries_by_category[i]: #if i == 4: # print item,unique_to_as_shown_map_by_category[i][item] mapped_unique.append(unique_to_as_shown_map_by_category[i][item]) unique_entries.append(mapped_unique) #unique_entries.append(entries_as_shown_by_category[i]) elif columntypes[i] != 'ID': unique_entries.append(unique_entries_by_category[i]) column_titles.remove(column_titles[columntypes.index('ID')]) columntypes.remove('ID') print 'Saving to disk...' outfile = file(mydir + '/' + thisfilename + '_processed.pcl','w') pickle.dump(column_titles,outfile) pickle.dump(columntypes,outfile) pickle.dump(unique_entries,outfile) pickle.dump(events_byID,outfile) outfile.close() print 'Done.' else: print 'Already have',thisfilename if not found: print "None found." except IOError: print "Unable to connect to Internet." def print_nicely_formatted(text,linelength): print text return i = 0 line = '' for word in text.split(): if i + 1 + len(word) > linelength: if len(line) < linelength: increment = float(linelength) / (linelength - len(line) + 1) line_words = line.split() line = '' index = increment for aword in line_words: if len(line) > 0: while (len(line) + len(aword) >= int(index)) and (len(line) + len(aword)) < linelength: line = line + ' ' index = index + increment line = line + aword + ' ' while len(line) >= int(index): line = line + ' ' index = index + increment print line line = word i = len(word) else: if i > 0: line = line + ' ' i = i + 1 line = line + word i = i + len(word) print line UTF8translation = dict() UTF8translation['\xe2\x80\x82'] = ' ' UTF8translation['\xe2\x80\x83'] = ' ' UTF8translation['\xe2\x80\x89'] = ' ' UTF8translation['\xe2\x80\x93'] = '-' UTF8translation['\xe2\x80\x94'] = '--' UTF8translation['\xe2\x80\x98'] = "'" UTF8translation['\xe2\x80\x99'] = "'" UTF8translation['\xe2\x80\x9A'] = "'" UTF8translation['\xe2\x80\x9C'] = '"' UTF8translation['\xe2\x80\x9D'] = '"' UTF8translation['\xe2\x80\x9E'] = '"' UTF8translation['\xe2\x80\xA0'] = '!' UTF8translation['\xe2\x80\xA1'] = '!' UTF8translation['\xe2\x80\xB0'] = '%o' UTF8translation['\xe2\x80\xB9'] = '<' UTF8translation['\xe2\x80\xBA'] = '>' UTF8translation['\xe2\x80\xAC'] = 'E' UTF8translation['\xe2\x80\xA2'] = '*' UTF8translation['\xe2\x80\xA6'] = '...' UTF8translation['\xe2\x80\xB2'] = "'" UTF8translation['\xe2\x80\xB3'] = '"' UTF8translation['\xe2\x80\xBE'] = '-' UTF8translation['\xe2\x81\x84'] = '/' print 'Welcome to Andrew\'s Gencon 2012 Schedule Solver' print 'This software is an experimental tool for solving schedules with events' print 'with many different slots, where there are large numbers of different combinations' print 'possible. Only designed to work with the specific format of the Gencon 2012 csv' print 'files. Use at your own risk.' print reply = raw_input("Download latest events from website?") if reply.lower().startswith('y'): #Get the calendar from the Gencon community site get_catalog('http://community.gencon.com/files/folders/pmcompletecatalogs/default.aspx') print 'Reading from disk...' mydir = 'Catalogs' filenames = listdir('.') if not mydir in filenames: mkdir(mydir) filenames = listdir(mydir) files = filter(lambda f:f.endswith('.pcl') and not f.endswith('schedule.pcl'),filenames) files.sort() column_titles = list() unique_entries = dict() events_byID = dict() for fn in files: print 'Loading from',fn infile = file(mydir + '/' + fn,'r') this_column_titles = pickle.load(infile) this_columntypes = pickle.load(infile) this_unique_entries = pickle.load(infile) this_events_byID = pickle.load(infile) infile.close() for i in range(len(this_column_titles)): ctitle = this_column_titles[i] if not ctitle in column_titles: column_titles.append(ctitle) if not unique_entries.has_key(i): unique_entries[i] = list() for entry in this_unique_entries[i]: if not entry in unique_entries[i]: unique_entries[i].append(entry) for eventID in this_events_byID: processed_event = list() this_file_event = this_events_byID[eventID] for i in range(len(column_titles)): item = this_unique_entries[i][this_file_event[i]] processed_event.append(unique_entries[i].index(item)) events_byID[eventID] = processed_event if len(events_byID) == 0: print 'No events found.' print 'Unable to do anything without a valid event file!' exit(1) print len(events_byID),'total events' number_of_colums = len(column_titles) is_tournament_index = None can_register = None round_number_index = None total_rounds_index = None start_index = None end_index = None title_index = None desc_index = None long_desc_index = None type_index = None system_index = None rules_index = None company_index = None gm_index = None email_index = None webaddress_index = None age_index = None location_index = None room_index = None table_index = None modified_index = None tickets_available_index = None cost_index = None for i in range(number_of_colums): if 'room' in column_titles[i].lower(): room_index = i if 'modified' in column_titles[i].lower(): modified_index = i if 'location' in column_titles[i].lower(): location_index = i if 'table' in column_titles[i].lower(): table_index = i if 'title' in column_titles[i].lower(): title_index = i if 'short desc' in column_titles[i].lower(): desc_index = i if 'long desc' in column_titles[i].lower(): long_desc_index = i if 'start ' in column_titles[i].lower(): start_index = i if 'end ' in column_titles[i].lower(): end_index = i if 'round number' in column_titles[i].lower(): round_number_index = i if 'total rounds' in column_titles[i].lower(): total_rounds_index = i if 'cost' in column_titles[i].lower(): cost_index = i if 'tourn' in column_titles[i].lower(): is_tournament_index = i if 'regist' in column_titles[i].lower(): can_register = i if 'type' in column_titles[i].lower(): type_index = i if 'system' in column_titles[i].lower(): system_index = i if 'rules' in column_titles[i].lower(): rules_index = i if 'edition' in column_titles[i].lower(): edition_index = i if 'group' in column_titles[i].lower(): company_index = i if 'company' in column_titles[i].lower(): company_index = i if 'gm' in column_titles[i].lower(): gm_index = i if 'email' in column_titles[i].lower(): email_index = i if 'web' in column_titles[i].lower(): webaddress_index = i if 'tickets ava' in column_titles[i].lower(): tickets_available_index = i if 'age ' in column_titles[i].lower(): age_index = i print print 'Event types found:' for i in range(len(unique_entries[type_index])): foo = len(filter(lambda e:events_byID[e][type_index] == i,events_byID.keys())) foo = str(foo) print ' ' * (5 - len(foo)),foo, print unique_entries[type_index][i] print VIG_events = list() tournament_prelim_events = list() tournament_final_events = list() tournament_generic_events = list() nontournament_prelim_events = list() nontournament_final_events = list() nontournament_generic_events = list() for eventID in events_byID.keys(): event = events_byID[eventID] event_is_tournament = unique_entries[is_tournament_index][event[is_tournament_index]] event_can_register = unique_entries[can_register][event[can_register]] if 'VIG' in event_can_register: VIG_events.append(eventID) elif event_is_tournament: if event_can_register.lower().startswith('yes'): tournament_prelim_events.append(eventID) elif 'generic' in event_can_register.lower(): tournament_generic_events.append(eventID) else: tournament_final_events.append(eventID) else: if event_can_register.lower().startswith('yes'): nontournament_prelim_events.append(eventID) elif 'generic' in event_can_register.lower(): nontournament_generic_events.append(eventID) else: nontournament_final_events.append(eventID) events_canprereg = tournament_prelim_events + nontournament_prelim_events + nontournament_final_events events_generic = tournament_generic_events + nontournament_generic_events tournament_eventID = tournament_prelim_events + tournament_final_events + tournament_generic_events tournament_eventID.sort() events_following = dict() for eventID in tournament_eventID: #for eventID in events_byID.keys(): event = events_byID[eventID] rounds_total = unique_entries[total_rounds_index][event[total_rounds_index]] round_number = unique_entries[round_number_index][event[round_number_index]] event_title = unique_entries[title_index][event[title_index]] event_desc = unique_entries[desc_index][event[desc_index]] if round_number < rounds_total: event_system = event[system_index] event_end = time.mktime(unique_entries[end_index][event[end_index]]) event_company = event[company_index] #print unique_entries[system_index][event_system], #print unique_entries[company_index][event_company] #print #print eventID #print event_title #print event_desc #print round_number, #print rounds_total #print time.strftime('%A %I:%M%p',unique_entries[start_index][event[start_index]]) proc_title = '' lastdigit = False skip = 0 for c in event_desc.lower(): if c.isalnum() or c == ':': proc_title = proc_title + c if c.isdigit(): lastdigit = True else: lastdigit = False elif c == ' ': if not lastdigit: proc_title = proc_title + ' ' elif c != '.': proc_title = proc_title + ' ' lastdigit = False proc_title = proc_title.split() alldays = ['monday','tuesday','wednesday','thursday','friday','saturday','sunday'] thisday = [] thistime = [] for item in proc_title: if item in alldays and item not in thisday: thisday.append(item) elif item == 'noon' or item == '12noon': thistime.append('12pm') elif (item.endswith('am') or item.endswith('pm')) and item[0].isdigit(): thistime.append(item) #if len(thisday) = 0: # thisday = alldays #print thisday,thistime possible_following_events = dict() events_following[eventID] = list() #for aneventID in events_byID.keys(): #for aneventID in tournament_prelim_events + tournament_final_events + tournament_generic_events: for aneventID in tournament_final_events + nontournament_final_events: timeok = True anevent = events_byID[aneventID] if len(thisday) != 0: timeok = False for item in thisday: timeok = timeok or item == time.strftime('%A',unique_entries[start_index][anevent[start_index]]).lower() if timeok and len(thistime) != 0: timeok = False for item in thistime: timeok = timeok or item == time.strftime('%I%p',unique_entries[start_index][anevent[start_index]]).lower().lstrip('0') timeok = timeok or item == time.strftime('%I:%M%p',unique_entries[start_index][anevent[start_index]]).lower().lstrip('0') if (timeok and anevent[system_index] == event_system and anevent[company_index] == event_company and time.mktime(unique_entries[start_index][anevent[start_index]]) >= event_end and #(event_desc != unique_entries[desc_index][anevent[desc_index]] or # event_title != unique_entries[title_index][anevent[title_index]]) and unique_entries[round_number_index][anevent[round_number_index]] > round_number and unique_entries[total_rounds_index][anevent[total_rounds_index]] == rounds_total and unique_entries[round_number_index][anevent[round_number_index]] >= round_number): #(unique_entries[total_rounds_index][anevent[total_rounds_index]] != rounds_total or #unique_entries[round_number_index][anevent[round_number_index]] != round_number)): rkey = str(int(unique_entries[round_number_index][anevent[round_number_index]]))# + '.' + \ # str(int(unique_entries[total_rounds_index][anevent[total_rounds_index]])) if not possible_following_events.has_key(rkey): possible_following_events[rkey] = list() possible_following_events[rkey].append(aneventID) #possible_following_events[aneventID] = unique_entries[title_index][anevent[title_index]] best_final = dict() akeys = possible_following_events.keys() akeys.sort() for akey in akeys: best_score = 0 best_final[akey] = list() for aneventID in possible_following_events[akey]: title = unique_entries[title_index][events_byID[aneventID][title_index]] maximum_match = max(map(lambda s:sum(map(lambda x,y:x == y,title,event_title[s:])),range(len(event_title)))) maximum_match = max(maximum_match, max(map(lambda s:sum(map(lambda x,y:x == y,title[s:],event_title)),range(len(title))))) #print '\t',maximum_match,title if maximum_match > best_score: best_final[akey] = list() best_score = maximum_match if maximum_match == best_score: #if maximum_match >= 5: best_final[akey].append(aneventID) #print best_final #best_final_events = list() akeys = best_final.keys() akeys.sort() for akey in akeys: events_following[eventID].append(best_final[akey]) ident_indices = [title_index,is_tournament_index,can_register,round_number_index,total_rounds_index, desc_index,type_index,system_index,rules_index,company_index] time_indices = [start_index,end_index,modified_index] line = '' command = '' foundevents = dict() schedule = list() #event_priority = list() list_start_offset = 0 solved_events = None registered_events = list() showevents = list() #print unique_entries[can_register] while not command == 'quit': line = raw_input(">") linesplit = mysplit(line) #print linesplit command = linesplit[0].lower() arguments = linesplit[1:] startindex = 0 endindex = -1 if len(arguments) == 1: if '-' in arguments[0]: spl_arguments = arguments[0].split('-') if len(spl_arguments) == 2 and spl_arguments[0].isdigit() and spl_arguments[1].isdigit(): startindex = int(spl_arguments[0]) endindex = int(spl_arguments[1]) elif arguments[0] == 'all': startindex = 1 endindex = len(foundevents.keys())+1 elif arguments[0].isdigit(): startindex = int(arguments[0]) endindex = startindex elif len(arguments) == 3: if arguments[0].isdigit() and arguments[1].lower() in ['-','to'] and arguments[2].isdigit(): startindex = int(arguments[0]) endindex = int(arguments[2]) if command == 'find': foundevents = find_events(arguments) foundeventkeys = foundevents.keys() #if len(foundeventkeys) > 30: # showevents = foundeventkeys[:30] if len(foundeventkeys) == 0: print 'No matching events.' showevents = list() else: showevents = foundeventkeys showevents.sort(key = lambda eventID:unique_entries[start_index][events_byID[foundevents[eventID][0]][start_index]]) index = 1 for eventkey in showevents[:30]: events = foundevents[eventkey] eventkey_int = map(int,eventkey.split()) print '#'+str(index)+':',unique_entries[title_index][eventkey_int[title_index]], if len(events) == 1: print else: print '('+str(len(events))+' events)' #for eventID in events: # print '\t',eventID #print index = index + 1 if len(foundeventkeys) > 30: print len(foundeventkeys)-30,'more events found, type "more" to see more,' print '"add " to add an event to your schedule, "browse" for detailed info' list_start_offset = 0 elif command == 'more': list_start_offset += 30 if list_start_offset > len(showevents): print 'No more events to show' else: for eventkey in showevents[list_start_offset:list_start_offset+30]: events = foundevents[eventkey] eventkey_int = map(int,eventkey.split()) print '#'+str(index)+':',unique_entries[title_index][eventkey_int[title_index]], if len(events) == 1: print else: print '('+str(len(events))+' events)' #for eventID in events: # print '\t',eventID #print index = index + 1 if len(foundeventkeys) > list_start_offset+30: print len(foundeventkeys)-(list_start_offset+30),'more events found, type "more" to see more.' print '"add " to add an event to your schedule, "browse" for detailed info' elif command == 'browse': list_start_offset = 0 done = False while not done: if list_start_offset >= len(foundeventkeys): done = True else: eventkey = showevents[list_start_offset] events = foundevents[eventkey] eventkey_int = map(int,eventkey.split()) print print_nicely_formatted(unique_entries[title_index][eventkey_int[title_index]],80) print_nicely_formatted(unique_entries[desc_index][eventkey_int[desc_index]],80) if eventkey_int[long_desc_index] >= 0: print_nicely_formatted(unique_entries[long_desc_index][eventkey_int[long_desc_index]],80) #print unique_entries[desc_index][eventkey_int[desc_index]] if len(events) == 1: event_ID = events[0] print event_ID, this_event = events_byID[event_ID] event_start = unique_entries[start_index][this_event[start_index]] event_end = unique_entries[end_index][this_event[end_index]] print time.strftime('%A %I:%M%p',event_start),'-', if time.strftime('%A',event_start) == time.strftime('%A',event_end): print time.strftime('%I:%M%p',event_end) else: print time.strftime('%A %I:%M%p',event_end) else: print '('+str(len(events))+' events)' #print location_index,room_index,table_index #print eventkey_int[location_index],eventkey_int[room_index],eventkey_int[table_index] if eventkey_int[location_index] != -1: print unique_entries[location_index][eventkey_int[location_index]], if eventkey_int[room_index] != -1: print unique_entries[room_index][eventkey_int[room_index]], if eventkey_int[table_index] != -1: print unique_entries[table_index][eventkey_int[table_index]] if eventkey_int[system_index] != -1: print unique_entries[system_index][eventkey_int[system_index]], if eventkey_int[rules_index] != -1: print unique_entries[rules_index][eventkey_int[rules_index]]+',', if eventkey_int[company_index] != -1: print unique_entries[company_index][eventkey_int[company_index]]+',', if eventkey_int[gm_index] != -1: print unique_entries[gm_index][eventkey_int[gm_index]], print if eventkey_int[cost_index] != -1: print 'Event cost:', print str(unique_entries[cost_index][eventkey_int[cost_index]]) + ',', tickets_remaining = 0 for event_ID in events: this_event = events_byID[event_ID] tickets_remaining = tickets_remaining + unique_entries[tickets_available_index][this_event[tickets_available_index]] print int(tickets_remaining), print "tickets remaining" list_start_offset = list_start_offset + 1 already_have = False for s in schedule: if len(s[1]) == len(events) and all(map(lambda e:e in s[1],events)): already_have = True #schedule = filter(lambda s:eventID not in s[1],schedule) if already_have: print 'Already in schedule, moving on...' else: reply = raw_input("Add/continue?") if reply.lower().startswith('n') or reply.lower().startswith('q'): done = True elif reply.lower().startswith('y') or reply.lower().startswith('q'): priority = raw_input('Priority for '+unique_entries[title_index][eventkey_int[title_index]]+'?') if priority.isdigit(): priority = int(priority) if priority < 0: priority = 0 elif priority > 10: priority = 10 schedule.append((priority,foundevents[eventkey])) #schedule.append((priority,unique_entries[title_index][eventkey_int[title_index]])) #event_priority.append(priority) if events_following.has_key(events[0]): print "Note:",unique_entries[title_index][eventkey_int[title_index]], print "is start of a tournament, will attempt to link rest of tournament events to it." elif command == 'show': for i in range(startindex - 1,endindex): if i >= 0 and i < len(showevents): eventkey = map(int,showevents[i].split()) events = foundevents[showevents[i]] #eventkey = map(int,foundevents.keys()[i].split()) for j in range(len(eventkey)): if eventkey[j] > -1 and j not in time_indices: print column_titles[j] + ':',unique_entries[j][eventkey[j]] for eventID in events: print '\t',eventID, print time.strftime('%A %I:%M%p',unique_entries[start_index][events_byID[eventID][start_index]]),'-', print time.strftime('%A %I:%M%p',unique_entries[end_index][events_byID[eventID][end_index]]) print #print eventkey elif command in ['add','got']: if len(arguments)>0 and events_byID.has_key(arguments[0]): eventID = arguments[0] priority = raw_input('Priority for '+eventID+'?') if priority.isdigit(): schedule = filter(lambda s:eventID not in s[1],schedule) priority = int(priority) if priority < 0: priority = 0 elif priority > 10: priority = 10 schedule.append((priority,[eventID])) if events_following.has_key(eventID): print "Note:",eventID, print " is start of a tournament, will attempt to link rest of tournament events to it." else: for i in range(startindex - 1,endindex): if i >= 0 and i < len(foundevents.keys()): eventkey_int = map(int,showevents[i].split()) priority = raw_input('Priority for '+unique_entries[title_index][eventkey_int[title_index]]+'?') if priority.isdigit(): priority = int(priority) if priority < 0: priority = 0 elif priority > 10: priority = 10 schedule.append((priority,foundevents[showevents[i]])) if events_following.has_key(foundevents[showevents[i]][0]): print "Note:",unique_entries[title_index][eventkey_int[title_index]], print "is start of a tournament, will attempt to link rest of tournament events to it." elif command == 'list': index = 1 schedule.sort(reverse = True) for index in range(len(schedule)): events = schedule[index][1] print '#'+str(index+1)+':', print unique_entries[title_index][events_byID[events[0]][title_index]], if len(events) > 1: print '('+str(len(events))+' events)', else: print events[0], print schedule[index][0] elif command in ['change']: if startindex <= endindex: changing_events = schedule[startindex - 1:endindex] schedule = schedule[:startindex - 1]+schedule[endindex:] for anevent_info in changing_events: anevent = events_byID[anevent_info[1][0]] priority = raw_input('Priority for '+unique_entries[title_index][anevent[title_index]]+'?') newevent_info = anevent_info if priority.isdigit(): priority = int(priority) if priority < 0: priority = 0 elif priority > 10: priority = 10 newevent_info = (priority,anevent_info[1]) schedule.append(newevent_info) elif command in ['combine','merge']: if startindex <= endindex: combinedevents = list() priority = schedule[startindex][0] for anevent_info in schedule[startindex - 1:endindex]: combinedevents = combinedevents + anevent_info[1] schedule = schedule[:startindex - 1]+schedule[endindex:] newevent_info = (priority,combinedevents) schedule.append(newevent_info) elif command in ['del','remove']: if len(arguments)>0 and events_byID.has_key(arguments[0]): eventID = arguments[0] schedule = map(lambda s:(s[0],filter(lambda e:e != eventID,s[1])),schedule) #print schedule schedule = filter(lambda s:len(s[1])>0,schedule) elif startindex <= endindex: schedule = schedule[:startindex - 1]+schedule[endindex:] #event_priority = event_priority[:startindex - 1]+event_priority[endindex:] elif command == 'solve': registered_events = list() solved_events = None all_solved_events = solve_schedule(schedule) if startindex > endindex: if all_solved_events and len(all_solved_events) > 0: solved_events = all_solved_events[0][1] if solved_events != None: print 'Schedules calculated.' print reply = raw_input('Proceed to registration?') if reply.lower().startswith('y'): events_remaining = True while events_remaining and all_solved_events != None: print "Calculating wish list..." print fail_check_events = list() #fail_check_list = list() #schedules_tocheck = [all_solved_events[0][1]] fully_solved_schedules = list() #while len(schedules_tocheck) > 0: for a_schedule in all_solved_events: #for a_schedule in schedules_tocheck: these_fail_check_events = list() for eventID in a_schedule[1]: if not eventID in fail_check_events+registered_events: thisevent = events_byID[eventID] if (int(float(unique_entries[cost_index][thisevent[cost_index]])) > 0 and not unique_entries[can_register][thisevent[can_register]].lower().startswith('no')): these_fail_check_events.append(eventID) #these_fail_check_events.sort(key = lambda e: # int(float(unique_entries[tickets_available_index][events_byID[e][tickets_available_index]]))) if len(these_fail_check_events) == 0: fully_solved_schedules.append(a_schedule) else: these_fail_check_events.sort(key = lambda e:max(map(lambda s:(e in s[1]) and len(s[1]),schedule))) #these_fail_check_events.reverse() for eventID in these_fail_check_events: #print eventID fail_check_events.append(eventID) fully_solved_schedules.sort(reverse = True) solved_events = fully_solved_schedules[0][1] if fully_solved_schedules[0] == all_solved_events[0]: fail_check_events = list() if len(registered_events) > 0: print 'Registered events:' for eventID in registered_events: print eventID+' ('+unique_entries[title_index][events_byID[eventID][title_index]]+')' print if len(fail_check_events) > 0: event_priority = 1 fail_check_events = fail_check_events[:20] print 'Wish list is as follows:' for eventID in fail_check_events: print event_priority,eventID+' ('+unique_entries[title_index][events_byID[eventID][title_index]]+')' event_priority = event_priority + 1 #print unique_entries[can_register][events_byID[eventID][can_register]] print 'Enter wish list in registration site now and submit form.' print #full_events = list() for eventID in fail_check_events: reply = raw_input('Did we get '+eventID+'?') if reply.lower().startswith('y'): registered_events.append(eventID) #schedule = filter(lambda s:eventID not in s[1],schedule) #schedule.append((10,[eventID])) else: schedule = map(lambda s:(s[0],filter(lambda e:e != eventID,s[1])),schedule) schedule = filter(lambda s:len(s[1]) > 0,schedule) print print 'Recalculating schedule now...' print solved_events = None all_solved_events = solve_schedule(schedule) if all_solved_events and len(all_solved_events) > 0: solved_events = all_solved_events[0][1] else: events_remaining = False if solved_events != None: drop_events = list() for eventID in registered_events: if not eventID in solved_events: drop_events.append(eventID) if len(drop_events) > 0: print 'Now remove the following events from your cart:' for eventID in drop_events: print eventID registered_events.remove(eventID) reply = raw_input('(Press Enter when finished)') print solved_events.sort(key = lambda eventID:unique_entries[start_index][events_byID[eventID][start_index]]) last_day = None for eventID in solved_events: if eventID in registered_events: schedule = filter(lambda s:eventID not in s[1],schedule) schedule.append((10,[eventID])) thisevent = events_byID[eventID] start_time = unique_entries[start_index][thisevent[start_index]] end_time = unique_entries[end_index][thisevent[end_index]] if last_day != time.strftime('%A',start_time): print print time.strftime('%A %d %B %Y',start_time) print last_day = time.strftime('%A',start_time) print_nicely_formatted(eventID + ': ' + unique_entries[title_index][thisevent[title_index]],80) whenst = time.strftime('%A %I:%M%p',start_time) + '-' if time.strftime('%A',end_time) != last_day: whenst = whenst + time.strftime('%A %I:%M%p',end_time) else: whenst = whenst + time.strftime('%I:%M%p',end_time) wherest = ' '.join([unique_entries[location_index][thisevent[location_index]], unique_entries[room_index][thisevent[room_index]], unique_entries[table_index][thisevent[table_index]]]) print_nicely_formatted(whenst + ', ' + wherest,80) event_desc = unique_entries[desc_index][thisevent[desc_index]] print_nicely_formatted(event_desc,80) whost = '' #print whost if len(unique_entries[gm_index][thisevent[gm_index]]) > 0: whost = whost + unique_entries[gm_index][thisevent[gm_index]] + ', ' #print whost,unique_entries[company_index][thisevent[company_index]] whost = whost + unique_entries[company_index][thisevent[company_index]] whost = ' '.join(map(lambda s:s.capitalize(),whost.split())) if unique_entries[cost_index][thisevent[cost_index]] > 0: whost = whost + ' $'+str(unique_entries[cost_index][thisevent[cost_index]]) print_nicely_formatted(whost,80) #print unique_entries[webaddress_index][thisevent[webaddress_index]], #print unique_entries[email_index][thisevent[email_index]] #print 'Tickets available:', #print unique_entries[tickets_available_index][thisevent[tickets_available_index]], #print 'Event cost:', #print unique_entries[cost_index][thisevent[cost_index]] print #if events_following.has_key(eventID): # print events_following[eventID] print else: print "Unable to solve schedule - incompatible mandatory events! Remove some or reduce priority below 10." else: if all_solved_events and len(all_solved_events) > 0: print 'Schedules calculated.' print for solved_event_info in all_solved_events[startindex - 1:endindex]: solved_events = solved_event_info[1] solved_events.sort(key = lambda eventID:unique_entries[start_index][events_byID[eventID][start_index]]) print 'Score:',solved_event_info[0] for eventID in solved_events: if eventID in registered_events: schedule = filter(lambda s:eventID not in s[1],schedule) schedule.append((10,[eventID])) thisevent = events_byID[eventID] start_time = unique_entries[start_index][thisevent[start_index]] end_time = unique_entries[end_index][thisevent[end_index]] whenst = time.strftime('%A %I:%M%p',start_time) + '-' whenst = whenst + time.strftime('%A %I:%M%p',end_time) wherest = ' '.join([unique_entries[location_index][thisevent[location_index]], unique_entries[room_index][thisevent[room_index]], unique_entries[table_index][thisevent[table_index]]]) if len(unique_entries[title_index][thisevent[title_index]]) > 25: print_nicely_formatted(whenst + ' ' + eventID + ': ' + unique_entries[title_index][thisevent[title_index]][:22] + '..., ' + wherest,80) else: print_nicely_formatted(whenst + ' ' + eventID + ': ' + unique_entries[title_index][thisevent[title_index]] + ', ' + wherest,80) print else: print "Unable to solve schedule - incompatible mandatory events! Remove some or reduce priority below 10." elif command == 'save': if len(arguments) > 0: print 'Saving to disk...' outfile = file(mydir + '/' + arguments[0] + '_schedule.pcl','w') pickle.dump(schedule,outfile) outfile.close() else: print "Not saved, file name needed" elif command == 'load': if len(arguments) > 0: print 'Loading from disk...' try: infile = file(mydir + '/' + arguments[0] + '_schedule.pcl','r') schedule = pickle.load(infile) infile.close() schedule = map(lambda s:(s[0],filter(lambda e:events_byID.has_key(e),s[1])),schedule) schedule = filter(lambda s:len(s[1])>0,schedule) except IOError: print arguments[0] + '_schedule.pcl not found.' schedule = list() else: print "Not loaded, file name needed" elif command == '?' or command == 'help': if len(arguments) == 0: print "Commands:" print print "quit - exits this program" print "find - searches the list of events for matches" print "more - lists next 30 found events" print "browse - views list of found events in detail one by one" print "show # - shows full details on one event" print "add # - adds an event from found event list to wishlist" print "list - shows your current wishlist" print "change # - changes the priority of an item on your wishlist" print "merge # - combines two items on wishlist into single item" print "del # - removes an item from your wishlist" print "solve - solves for best schedules, optionally proceeds to registration" print "save - saves current wishlist to a file" print "load - loads current wishlist from a file" print "help - more detailed information on that command" print print "Commands are not case-sensitive" elif arguments[0] == 'find': print 'save ' print print 'This searches the list of events according to keywords' print 'Accepted keywords are any, all, on, in, at, by, before, after, type, not, age' print print 'Keyword functions:' print print 'Any, All - followed by a word this searches for all events which contain that word in their' print 'title or description. For example, "Find all NASCRAG". You can also omit the keyword for' print 'this case and just type "Find NASCRAG"/' print print 'on - searches for events by day' print ' for example, "find on saturday"' print print 'in - searches for events by location' print ' for example, "find in hyatt"' print print 'by - searches for events by company or group' print ' for example, "find by gamebase7"' print print 'before - searches for events which take place before a certain time' print ' for example, "find before 10pm"' print print 'after - searches for events which take place after a certain time' print ' for example, "find after 10am"' print print 'type - searches by the prefix/type code of the event' print ' for example, "find type RPGA"' print print 'not - inverts action of following keywords' print ' for example, "find not on sunday"' print print 'age - searches by event age restriction' print ' for example, "find age 21+"' print print 'Multiple keyword searches can be combines into a single search line' print ' for example, "find sparks by gamebase7 after 1pm not on thursday"' print print 'This command will return a numbered list of all events matching the search terms' print 'and will display the first 30 matches' elif arguments[0] == 'more': print 'more' print print 'The command Find will only show the first 30 event matches' print 'Typing "more" will then show the next 30 matches' elif arguments[0] == 'browse': print 'browse' print print 'After running the find command to generate a list of matches, the browse command' print 'will show each matching event one by one in detail, and for each one give the option to add' print 'that event to your wish list' print print 'When you add an item to your wish list, you will be asked for a priority number, which' print 'should be a number from 1-10. A priority of 10 indicates a must-have event - the script' print 'will reject any calendar which does not include that event. Lower priority events will' print 'be added as possible in order of their priority number' elif arguments[0] == 'show': print 'show #' print print 'After running the find command to generate a list of matches, the show command will' print 'give you all the details of an item on the list.' elif arguments[0] == 'add': print 'show #' print print 'After running the find command to generate a list of matches, the add command will' print 'allow you to add a single entry from the list to your wishlist.' print print 'When you add an item to your wish list, you will be asked for a priority number, which' print 'should be a number from 1-10. A priority of 10 indicates a must-have event - the script' print 'will reject any calendar which does not include that event. Lower priority events will' print 'be added as possible in order of their priority number' elif arguments[0] == 'list': print 'list' print print 'This command shows your wishlist so far, giving you an index list of event name,' print 'event number or number of event slots, and priority' elif arguments[0] == 'change': print 'change #' print print 'After running the list command, this command allows you to change the priority of' print 'any entry on the wishlist.' elif arguments[0] == 'merge': print 'merge #' print print 'This is a semi-experimental command which allows you to combine two items on your wishlist' print 'This is used primarily for merging two items which are the same event but weren\'t properly' print 'combined by the catelog parses. To use this, add both the events you want to combine to' print 'your wishlist, giving them both the same priority so they will show up as adjacent items.' print 'Then use the merge command to join them, for example merge 4-5 if they are items 4 and 5.' print 'This can also be used when you have a situation where you want to go to either event A or' print 'event B but not both, by merging them into a single event with multiple slots.' elif arguments[0] == 'del': print 'del #' print print 'After running the list command, this command allows you to remove any one item from your' print 'wishlist.' elif arguments[0] == 'solve': print 'solve' print print 'This command attempts to derive an optimal schedule from your wishlist. This command takes' print 'into account all of the events you have selected, and the priority which you have assigned' print 'to each one. It then builds a list of all possible schedule combinations and then ranks' print 'them by desirability. When doing so it attempts to get in as many events as possible, but' print 'also prefers events in the afternoon or evening over those very late or early, and when' print 'possible tries to give you at least 15 minutes between events.' print print 'After the schedules are produced, you will be given the option to proceed to registration.' print 'The script does not fill out the Gencon registration page for you, you have to do that' print 'manually.' print 'However, it will give you a list of event IDs to enter. Do not be alarmed if you see' print 'muliple conflicting events in the event ID list - the script takes a greedy approach where' print 'it has you register for all event slots you might want, then depending on which ones you get' print 'has you drop some of them later. Just follow the instructions the script prints out, and' print 'follow the prompts to tell the script which slots you actually managed to get. When that is' print 'done, the script will generate a finished schedule for you to copy and print out.' print print 'The script does not instruct you to register for free events that do not requie pre-reg,' print 'such as seminars. You should probably register for them anyway afterwards.' print print 'The script attempts to take tournament structure into account. If you register for the' print 'first part of a tournament, it will attempt to find the other parts of the tournament and' print 'add them to your schedule. This doesn\'t always work.' print print 'If you answer no to the prompt to proceed to registration, the script will then just print' print 'out your optimal schedule - the one you\'ll have if you manage to get every event you try to' print 'register for.' elif arguments[0] == 'save': print 'save ' print print 'This command immedately saves the current wishlist to a file indicated by the filename' print 'This overwrites any existing file of that name without warning.' elif arguments[0] == 'load': print 'save ' print print 'This command immedately loads the wishlist from a file indicated by the filename' print 'This overwrites the curent wishlist without warning.' else: print 'No help available for',arguments[0] elif command == 'quit' or command == '': pass else: print 'Unrecognized command:',command