This is as it evolved. I can't be bothered to look if optimisation is possible.
********************************
# start get data
input_file = open("16Input.txt", "r")
data = [line.strip() for line in input_file]
input_file.close()
#format data
rules = []
tickets = []
section = "rules"
for d in data:
if d!="":
if section == "rules":
if d.split()[0]=="your":
section = "tickets"
else:
rules.append([d.split(": ")[0], d.split(": ")[1].split(" or ")[0].split("-"), d.split(": ")[1].split(" or ")[1].split("-")])
else:
dw1 = d.split()[0]
if dw1!="" and dw1!="nearby":
tickets.append(d.split(","))
#part 1
error_rate = 0
for tindex, ticket in enumerate(tickets):
for val in ticket:
value = int (val)
valid = False
for rule in rules:
range1 = range(int(rule[1][0]),int(rule[1][1])+1)
range2 = range(int(rule[2][0]),int(rule[2][1])+1)
if value in range1 or value in range2:
valid = True
if not valid:
error_rate += value
tickets[tindex][0]="invalid"
print (error_rate) #Part 1
#Part 2
#Create a matrix of rules (rows) and fields (columns) which are vaild for the rule
rule_valid = []
for r in rules:
rule_valid.append ([r[0]+"........................."[:-len(r[0])]])
for rindex, rule in enumerate(rules):
fvcount = 0
range1 = range(int(rule[1][0]),int(rule[1][1])+1)
range2 = range(int(rule[2][0]),int(rule[2][1])+1)
for field in range (len (tickets[0])):
field_valid = True
for tindex, ticket in enumerate(tickets):
if ticket
tick_f = int(ticket[field])
if tick_f not in range1 and tick_f not in range2: #rule invalid for field on this ticket
field_valid = False
if field_valid:
rule_valid[rindex].append(1)
fvcount+=1
else:
rule_valid[rindex].append(0)
rule_valid[rindex].append(fvcount) #tag a count of how many fields are valid to the end of the rule row.
#scan the matrix to decide which field is applicable to which rule
available_flds = [True]*20
for valid_fld_cnt in range (21):
for rindex, rv in enumerate(rule_valid):
if rv[-1] == valid_fld_cnt:
for field in range (len (tickets[0])):
if rv[field+1]==1 and available_flds[field]:
rule_valid[rindex].append(field)
available_flds[field]=False
#print the buggers out, and calc the answer.
dep_multi = 1
for rv in rule_valid:
print (rv)
if rv[0][:9]=="departure":
num = int(tickets[0][rv[-1]]) #field from my ticket
dep_multi *= num
print (dep_multi)