Task 15.1, 16.1, 16.2. Naive solution for 15.2, should use A*

This commit is contained in:
2021-12-16 11:46:20 +03:00
parent 1c9a6c0a96
commit a5957c7f07
6 changed files with 395 additions and 0 deletions
+134
View File
@@ -0,0 +1,134 @@
from math import prod
with open("input") as f:
data = f.read().strip()
trt = {x: list(f'{int(x, base=16):04b}') for x in '0123456789ABCDEF'}
def take(n, rest, tail, tr):
if not tr:
l = len(rest)
return list(rest)+list(tail[:n-l]), [], tail[n-l:]
head = []
while n>len(rest) and tail:
head += rest
n -= len(rest)
a, *tail = tail
rest = trt[a]
head += rest[:n]
rest = rest[n:]
return head, rest, tail
def make_val(r, t, tr):
val = []
h, r, t = take(5, r, t, tr)
while h[0]!='0':
val.extend(h[1:])
h, r, t = take(5, r, t, tr)
val.extend(h[1:])
val = int(''.join(val), base=2)
return val, r, t
def make_by_len(r, t, tr):
res = []
while t:
pak, r, t = make_pak(r, t, tr)
res.append(pak)
return res
def make_by_count(l, r, t, tr):
res = []
for _ in range(l):
pak, r, t = make_pak(r, t, tr)
res.append(pak)
return res, r, t
def make_pak(r, t, tr):
h, r, t = take(3, r, t, tr)
ver = ''.join(h)
h, r, t = take(3, r, t, tr)
typ = ''.join(h)
if typ=='100':
val, r, t = make_val(r, t, tr)
return (ver, typ, val), r, t
else:
(ltid,), r, t = take(1, r, t, tr)
if ltid=='0':
l, r, t = take(15, r, t, tr)
l = int(''.join(l), base=2)
h, r, t = take(l, r, t, tr)
return (ver, typ, make_by_len([], h, tr=False)), r, t
else:
l, r, t = take(11, r, t, tr)
l = int(''.join(l), base=2)
paks, r, t = make_by_count(l, r, t, tr)
return (ver, typ, paks), r, t
def sum_ver(pak):
ver, typ, val = pak
if typ=='100':
return int(ver, base=2)
else:
return int(ver, base=2)+sum(sum_ver(pak) for pak in val)
def test_a():
paks, _ ,_ = make_by_count(1, [], list('D2FE28'), True)
assert paks[0][2] == 2021
def test_b():
paks, _ ,_ = make_by_count(1, [], list('38006F45291200'), True)
p1, p2 = paks[0][2]
assert p1[2]==10 and p2[2]==20
def test_c():
paks, _ ,_ = make_by_count(1, [], list('EE00D40C823060'), True)
p1, p2, p3 = paks[0][2]
assert p1[2]==1 and p2[2]==2 and p3[2]==3
def test_1():
paks, _ ,_ = make_by_count(1, [], list('8A004A801A8002F478'), True)
assert sum_ver(paks[0])==16
def test_2():
paks, _ ,_ = make_by_count(1, [], list('620080001611562C8802118E34'), True)
sum_ver(paks[0])==12
def test_3():
paks, _ ,_ = make_by_count(1, [], list('C0015000016115A2E0802F182340'), True)
sum_ver(paks[0])==23
def test_4():
paks, _ ,_ = make_by_count(1, [], list('A0016C880162017C3686B18A3D4780'), True)
sum_ver(paks[0])==31
def test_bug1():
_, r, t = take(22, [], list('C0015000016115A2E0802F182340'), True)
_, r, t = take(84, r, t, True)
assert len(r)==2 and len(t)==1
def calculate(pak):
ver, typ, val = pak
typ = int(typ, base=2)
if typ==0:
return sum(calculate(pak) for pak in val)
elif typ==1:
return prod(calculate(pak) for pak in val)
elif typ==2:
return min(calculate(pak) for pak in val)
elif typ==3:
return max(calculate(pak) for pak in val)
elif typ==4:
return val
elif typ==5:
p1, p2 = val
return 1 if calculate(p1)>calculate(p2) else 0
elif typ==6:
p1, p2 = val
return 1 if calculate(p1)<calculate(p2) else 0
elif typ==7:
p1, p2 = val
return 1 if calculate(p1)==calculate(p2) else 0
else:
raise ValueError('Incorrect packet type')
if __name__ == '__main__':
paks, _ ,_ = make_by_count(1, [], list(data), True)
print(sum_ver(paks[0]))
print(calculate(paks[0]))
+1
View File
@@ -0,0 +1 @@
4057231006FF2D2E1AD8025275E4EB45A9ED518E5F1AB4363C60084953FB09E008725772E8ECAC312F0C18025400D34F732333DCC8FCEDF7CFE504802B4B00426E1A129B86846441840193007E3041483E4008541F8490D4C01A89B0DE17280472FE937C8E6ECD2F0D63B0379AC72FF8CBC9CC01F4CCBE49777098D4169DE4BF2869DE6DACC015F005C401989D0423F0002111723AC289DED3E64401004B084F074BBECE829803D3A0D3AD51BD001D586B2BEAFFE0F1CC80267F005E54D254C272950F00119264DA7E9A3E9FE6BB2C564F5376A49625534C01B0004222B41D8A80008446A8990880010A83518A12B01A48C0639A0178060059801C404F990128AE007801002803AB1801A0030A280184026AA8014C01C9B005CE0011AB00304800694BE2612E00A45C97CC3C7C4020A600433253F696A7E74B54DE46F395EC5E2009C9FF91689D6F3005AC0119AF4698E4E2713B2609C7E92F57D2CB1CE0600063925CFE736DE04625CC6A2B71050055793B4679F08CA725CDCA1F4792CCB566494D8F4C69808010494499E469C289BA7B9E2720152EC0130004320FC1D8420008647E8230726FDFED6E6A401564EBA6002FD3417350D7C28400C8C8600A5003EB22413BED673AB8EC95ED0CE5D480285C00372755E11CCFB164920070B40118DB1AE5901C0199DCD8D616CFA89009BF600880021304E0EC52100623A4648AB33EB51BCC017C0040E490A490A532F86016CA064E2B4939CEABC99F9009632FDE3AE00660200D4398CD120401F8C70DE2DB004A9296C662750663EC89C1006AF34B9A00BCFDBB4BBFCB5FBFF98980273B5BD37FCC4DF00354100762EC258C6000854158750A2072001F9338AC05A1E800535230DDE318597E61567D88C013A00C2A63D5843D80A958FBBBF5F46F2947F952D7003E5E1AC4A854400404A069802B25618E008667B7BAFEF24A9DD024F72DBAAFCB312002A9336C20CE84