You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
358 lines
7.3 KiB
358 lines
7.3 KiB
#!/usr/bin/env python
|
|
|
|
from aoc import get_input # AoC
|
|
import re # regex
|
|
|
|
data = get_input(16).strip()
|
|
|
|
stuff = data.split("\n\n")
|
|
|
|
params = stuff[0].split("\n")
|
|
myticket = stuff[1].split("\n")[1]
|
|
tickets = stuff[2].split("\n")
|
|
tickets.pop(0)
|
|
|
|
|
|
def parseParam(param):
|
|
name, rnga1, rnga2, rngb1, rngb2 = re.match(r"([a-z\ ]+): ([0-9]+)-([0-9]+) or ([0-9]+)-([0-9]+)", param).groups()
|
|
|
|
rng1 = range(int(rnga1), int(rnga2) + 1)
|
|
rng2 = range(int(rngb1), int(rngb2) + 1)
|
|
|
|
return name, rng1, rng2
|
|
|
|
ranges = dict()
|
|
for i in range(len(params)):
|
|
par = params[i]
|
|
name, rng1, rng2 = parseParam(par)
|
|
ranges[name] = (rng1, rng2)
|
|
|
|
|
|
def parseTicket(ticket):
|
|
return [int(n) for n in ticket.split(",")]
|
|
|
|
badvals = []
|
|
|
|
goodtickets = [ti for ti in tickets]
|
|
badtickets = []
|
|
|
|
for i in range(len(tickets)):
|
|
if( i > 0 ):
|
|
ticket = tickets[i]
|
|
vals = parseTicket(ticket)
|
|
|
|
for v in vals:
|
|
checks = []
|
|
for cl, rng in ranges.items():
|
|
for r in rng:
|
|
checks.append( v in r )
|
|
|
|
valid = any(check for check in checks)
|
|
|
|
if(not valid):
|
|
badvals.append(v)
|
|
break
|
|
|
|
if( not valid ):
|
|
print(f"Bad: {ticket=} {any(checks)=}")
|
|
goodtickets.remove(ticket)
|
|
badtickets.append(ticket)
|
|
|
|
|
|
print("\nPart1:", sum(badvals))
|
|
|
|
# freeranges = ranges
|
|
|
|
# def getClass(num):
|
|
# out = None
|
|
# for cl, rng in freeranges.items():
|
|
# check1 = num in rng[0]
|
|
# check2 = num in rng[1]
|
|
# check = check1 or check2
|
|
|
|
# if(check):
|
|
# freeranges.pop(cl, None)
|
|
# out = cl
|
|
|
|
# break
|
|
# else:
|
|
# continue
|
|
|
|
# return out
|
|
|
|
# def getClass2(num):
|
|
# out = None
|
|
# for cl, rng in ranges.items():
|
|
# check1 = num in rng[0]
|
|
# check2 = num in rng[1]
|
|
# check = check1 or check2
|
|
|
|
# if(check):
|
|
# out = cl
|
|
|
|
# break
|
|
# else:
|
|
# continue
|
|
|
|
# return out
|
|
|
|
# print( getClass(3) )
|
|
# print( getClass(9) )
|
|
# print( getClass(18) )
|
|
# print("\n\n\n")
|
|
|
|
import itertools
|
|
import operator
|
|
|
|
def most_common(L):
|
|
SL = sorted((x, i) for i, x in enumerate(L))
|
|
groups = itertools.groupby(SL, key=operator.itemgetter(0))
|
|
def _auxfun(g):
|
|
item, iterable = g
|
|
count = 0
|
|
min_index = len(L)
|
|
for _, where in iterable:
|
|
count += 1
|
|
min_index = min(min_index, where)
|
|
return count, -min_index
|
|
return max(groups, key=_auxfun)[0]
|
|
|
|
seenindex = []
|
|
classIndex = dict()
|
|
|
|
#goodtickets.insert( 0, myticket )
|
|
print("####", len(goodtickets), "/" , len(tickets), "valid")
|
|
|
|
goodtickets = [ parseTicket(t) for t in goodtickets ]
|
|
|
|
|
|
def possibleParams(num):
|
|
possible = []
|
|
for cl, rng in ranges.items():
|
|
check1 = num in rng[0]
|
|
check2 = num in rng[1]
|
|
check = check1 or check2
|
|
|
|
if(check):
|
|
print(f"POSSIBLE {num=} {cl=}")
|
|
possible.append(cl)
|
|
|
|
return possible
|
|
|
|
from collections import defaultdict as dd
|
|
|
|
probIndex = dd(dict)
|
|
|
|
#print("22222", goodtickets[0])
|
|
|
|
|
|
# go through each param
|
|
# get possible indexs
|
|
# take least from possible
|
|
# add index to seen
|
|
|
|
print(params)
|
|
|
|
# for param, rng in ranges.items():
|
|
# print("\nchecking param", param)
|
|
# possible = {
|
|
# 0: 0,
|
|
# 1: 0,
|
|
# 2: 0,
|
|
# 3: 0,
|
|
# 4: 0,
|
|
# 5: 0,
|
|
# 6: 0,
|
|
# 7: 0,
|
|
# 8: 0,
|
|
# 9: 0,
|
|
# 10: 0,
|
|
# 11: 0,
|
|
# 12: 0,
|
|
# 13: 0,
|
|
# 14: 0,
|
|
# 15: 0,
|
|
# 16: 0,
|
|
# 17: 0,
|
|
# 18: 0,
|
|
# 19: 0
|
|
# }
|
|
|
|
# for ticket in tickets:
|
|
# for i in range(len(parseTicket(ticket))):
|
|
# n = parseTicket(ticket)[i]
|
|
|
|
# checks = []
|
|
# for r in rng:
|
|
# checks.append( n in r )
|
|
|
|
# valid = any(check for check in checks)
|
|
|
|
# print(f"Possible {rng=} {n=} {i=} {param=}", end="")
|
|
|
|
# if(valid):
|
|
# print(" +1")
|
|
# possible[i] += 1
|
|
# else:
|
|
# print("")
|
|
|
|
# probIndex[param] = possible
|
|
|
|
def numIsValid(num, rng):
|
|
checks = []
|
|
for r in rng:
|
|
checks.append( num in r )
|
|
|
|
valid = any(check for check in checks)
|
|
return valid
|
|
|
|
|
|
for i in range( len(goodtickets[0]) ):
|
|
validcls = []
|
|
|
|
for ticket in goodtickets:
|
|
num = ticket[i]
|
|
|
|
for cl, rng in ranges.items():
|
|
valid = numIsValid(num, rng)
|
|
|
|
if(valid):
|
|
validcls.append(cl)
|
|
|
|
probIndex[i] = validcls
|
|
|
|
|
|
seenIndex = []
|
|
seenValid = []
|
|
paramPos = dict()
|
|
print("\n\nTHING")
|
|
|
|
for chari in range( len(goodtickets[0]) ):
|
|
if( not chari in seenIndex ):
|
|
valids = probIndex[chari]
|
|
|
|
least = 99999999
|
|
leastparam = None
|
|
for v in valids:
|
|
if( valids.count(v) < least and not v in seenValid ):
|
|
least = valids.count(v)
|
|
leastparam = v
|
|
|
|
print(f"{least=} {leastparam=} {valids=}")
|
|
|
|
paramPos[chari] = leastparam
|
|
|
|
seenIndex.append(chari)
|
|
seenValid.append(leastparam)
|
|
|
|
print(paramPos)
|
|
|
|
|
|
# for param, pos in probIndex.items():
|
|
# if(param in seen):
|
|
# continue
|
|
|
|
# print("\n", param)
|
|
|
|
# for i, val in probIndex[param].items():
|
|
# print(i, val)
|
|
|
|
|
|
print(paramPos)
|
|
|
|
# for i in range(len(goodtickets[0])):
|
|
# posParams = [ possibleParams( goodtickets[0][i] ) ]
|
|
|
|
# for j in range(1, len(goodtickets)):
|
|
# tick = goodtickets[j]
|
|
# n = tick[i]
|
|
# pos = possibleParams( n )
|
|
|
|
# posParams.append(pos)
|
|
|
|
# probIndex[i] = posParams
|
|
|
|
|
|
# print(len(probIndex[19]))
|
|
|
|
# def checkParamForIndex(i, p):
|
|
# params = probIndex[i]
|
|
# # check = all( p in ticket for ticket in params )
|
|
# # print("###############", check, len(params))
|
|
|
|
|
|
|
|
|
|
# for i in range(len(goodtickets[0])):
|
|
# num = goodtickets[0][i]
|
|
# numcl = [ getClass(num) ]
|
|
|
|
# for j in range(0, len(goodtickets)):
|
|
# tick = goodtickets[j]
|
|
# n = tick[i]
|
|
# nclass = getClass2(n)
|
|
# if(nclass):
|
|
# numcl.append(nclass)
|
|
|
|
# common = most_common(numcl)
|
|
# same_count = numcl.count(common)
|
|
# r = (same_count / len(goodtickets)) * 100
|
|
# print(f"{i=} {num=} {common=} {same_count=} {r=}% {numcl[0]=}")
|
|
# probIndex[common][i] = r
|
|
|
|
# print(probIndex)
|
|
|
|
# paramIndex = dict()
|
|
|
|
# for parameter, probs in probIndex.items():
|
|
# lastProb = 0
|
|
# bestIndex = None
|
|
# for i, prob in probs.items():
|
|
# if( prob > lastProb ):
|
|
# lastProb = prob
|
|
# bestIndex = i
|
|
|
|
# paramIndex[parameter] = bestIndex
|
|
|
|
# print("######", paramIndex)
|
|
|
|
|
|
# for ticket in tickets:
|
|
# if( ticket in badtickets ):
|
|
# continue
|
|
# #print(ticket)
|
|
|
|
# p = parseTicket(ticket)
|
|
|
|
# for i in range(len(p)):
|
|
# check = not i in seenindex
|
|
|
|
# if( check ):
|
|
|
|
# num = p[i]
|
|
# cl = getClass(num)
|
|
# classIndex[cl] = i
|
|
# seenindex.append(i)
|
|
|
|
# continue
|
|
|
|
|
|
myticket = parseTicket(myticket)
|
|
thenums = []
|
|
|
|
# for cl, i in paramIndex.items():
|
|
# if( "departure" in cl ):
|
|
# thenums.append( myticket[i] )
|
|
|
|
print(thenums)
|
|
|
|
import math
|
|
|
|
print(" 1409959524847 !=")
|
|
print("#",math.prod(thenums))
|
|
print(" 21095351239483")
|
|
print(" 30145908219919 reverse")
|
|
|
|
print(sum(thenums))
|
|
|
|
print(classIndex)
|
|
|