Skip to content

Commit 66c87df

Browse files
committed
golf optimization: eliminate defaultdict where possible
1 parent 96ffa88 commit 66c87df

34 files changed

+83
-95
lines changed

2017/08/README.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -38,5 +38,5 @@ Your puzzle answer was `5035`.
3838

3939
A refreshingly simple puzzle, the most complicated part of which is parsing the input. The meat of the parse-and-execute loop fits into a mere three Python statements (`for`>`if`>`+=`).
4040

41-
* Part 1, Python: 308 bytes, <100 ms
42-
* Part 2, Python: 320 bytes, <100 ms
41+
* Part 1, Python: 291 bytes, <100 ms
42+
* Part 2, Python: 303 bytes, <100 ms

2017/08/aoc2017_08_part1.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
import re,collections as C
1+
import re
22
from operator import*
3-
m=C.defaultdict(int)
3+
m={}
44
for d,o,i,s,c,r in(re.match('(\w+) (inc|dec) (-?\d+) if (\w+) ([<>=!]=?) (-?\d+)',x).groups()for x in open("input.txt")):
5-
if{'<':lt,'>':gt,'==':eq,'!=':ne,'>=':ge,'<=':le}[c](m[s],int(r)):m[d]+=int(i)*(1-2*(o<'i'))
5+
if{'<':lt,'>':gt,'==':eq,'!=':ne,'>=':ge,'<=':le}[c](m.get(s,0),int(r)):m[d]=m.get(d,0)+int(i)*(1-2*(o<'i'))
66
print max(m.values())

2017/08/aoc2017_08_part2.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
import re,collections as C
1+
import re
22
from operator import*
3-
m,z=C.defaultdict(int),0
3+
m,z={},0
44
for d,o,i,s,c,r in(re.match('(\w+) (inc|dec) (-?\d+) if (\w+) ([<>=!]=?) (-?\d+)',x).groups()for x in open("input.txt")):
5-
if{'<':lt,'>':gt,'==':eq,'!=':ne,'>=':ge,'<=':le}[c](m[s],int(r)):m[d]+=int(i)*(1-2*(o<'i'))
5+
if{'<':lt,'>':gt,'==':eq,'!=':ne,'>=':ge,'<=':le}[c](m.get(s,0),int(r)):m[d]=m.get(d,0)+int(i)*(1-2*(o<'i'))
66
z=max(z,*m.values())
77
print z

2017/22/README.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -213,5 +213,5 @@ Your puzzle answer was `2512225`.
213213

214214
Part 1 is a simulation of the well-known [Langton's Ant](https://en.wikipedia.org/wiki/Langton's_ant), and part 2 is a specific [Turmite](https://en.wikipedia.org/wiki/Turmite) variant that interestingly shows purely chaotic behavior. Overall a fun puzzle where complex numbers come in handy for code golf. Note how part 2's rules, while seemingly much more complex, don't translate into significantly more code.
215215

216-
* Part 1, Python: 257 bytes, <100 ms
217-
* Part 2, Python: 266 bytes, ~5 s
216+
* Part 1, Python: 220 bytes, <100 ms
217+
* Part 2, Python: 229 bytes, ~5 s

2017/22/aoc2017_22_part1.py

+2-3
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
_=enumerate
2-
from collections import*
32
M,n=[],0
43
for y,r in _(open("input.txt")):M+=[(x,y,c=='#')for x,c in _(r)]
54
p=max(M);p=p[0]/2-p[1]/2j;d=-1j
6-
M=defaultdict(int,((x+y*1j,c)for x,y,c in M))
7-
for t in range(10000):M[p]=s=1-M[p];d*=(1-2*s)*1j;n+=s;p+=d
5+
M={x+y*1j:c for x,y,c in M}
6+
for t in range(10000):M[p]=s=1-M.get(p,0);d*=(1-2*s)*1j;n+=s;p+=d
87
print n

2017/22/aoc2017_22_part2.py

+2-3
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
_=enumerate
2-
from collections import*
32
M,n=[],0
43
for y,r in _(open("input.txt")):M+=[(x,y,2*(c=='#'))for x,c in _(r)]
54
p=max(M);p=p[0]/2-p[1]/2j;d=-1j
6-
M=defaultdict(int,((x+y*1j,c)for x,y,c in M))
7-
for t in range(10**7):M[p]=s=(M[p]+1)&3;d*=-1j**s;n+=(s==2);p+=d
5+
M={x+y*1j:c for x,y,c in M}
6+
for t in range(10**7):M[p]=s=(M.get(p,0)+1)&3;d*=-1j**s;n+=(s==2);p+=d
87
print n

2017/25/README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -87,4 +87,4 @@ The _garbage collector_ winks at you, then continues sweeping.
8787

8888
The most complicated part of this puzzle is parsing the input; the actual simulation is just a single line.
8989

90-
* Part 1, Python: 319 bytes, ~5 s
90+
* Part 1, Python: 292 bytes, ~5 s

2017/25/aoc2017_25.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
import re,collections as C
1+
import re
22
I,F=open("input.txt").read(),re.findall
33
s,t,d=F('ate (\w)',I),map(int,F('\d+',I)),F('rig|le',I)
44
P={s[3*i+1]:[(t[4*i+2*j+2],1-2*(d[2*i+j]<'r'),s[3*i+j+2])for j in(0,1)]for i in range(len(d)/2)}
5-
m,p=C.defaultdict(int),0
6-
for x in range(t[0]):m[p],d,s[0]=P[s[0]][m[p]];p+=d
5+
m,p={},0
6+
for x in range(t[0]):m[p],d,s[0]=P[s[0]][m.get(p,0)];p+=d
77
print sum(m.values())

2018/02/README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -54,5 +54,5 @@ Your puzzle answer was `prtkqyluiusocwvaezjmhmfgx`.
5454

5555
A rather straightforward puzzle; nothing to note here.
5656

57-
* Part 1, Python: 158 bytes, <100 ms
57+
* Part 1, Python: 129 bytes, <100 ms
5858
* Part 2, Python: 135 bytes, <100 ms

2018/02/aoc2018_02_part1.py

+2-3
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
1-
from collections import*
21
n={2:0,3:0}
32
for x in open("input.txt"):
4-
h=defaultdict(int)
5-
for l in x:h[l]+=1
3+
h={}
4+
for l in x:h[l]=h.get(l,0)+1
65
for i in(2,3):n[i]+=i in h.values()
76
print n[2]*n[3]

2018/03/README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -66,5 +66,5 @@ Your puzzle answer was `656`.
6666

6767
The apparent 1Kx1K problem size turned out to be a much smaller problem than it seemed, as the patches are very small and the resulting list of occupied fields is quite sparse.
6868

69-
* Part 1, Python: 222 bytes, ~350 ms
69+
* Part 1, Python: 197 bytes, ~350 ms
7070
* Part 2, Python: 291 bytes, ~1 s

2018/03/aoc2018_03_part1.py

+2-3
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
_=range
22
import re
3-
from collections import*
4-
d=defaultdict(int)
3+
d={}
54
for i,x,y,w,h in(map(int,re.findall('\d+',x))for x in open("input.txt")):
65
for y in _(y,y+h):
7-
for j in _(x,x+w):d[(j,y)]+=1
6+
for j in _(x,x+w):d[(j,y)]=d.get((j,y),0)+1
87
print sum(v>1for v in d.values())

2018/22/README.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -353,5 +353,5 @@ Part 2 is quite different: On the surface, it's a normal pathfinding puzzle, but
353353
I have two versions: A straightforward BFS implementation, and another version that strictly decomposes the tool changing and moving steps. The latter version turned out smaller and three times faster.
354354

355355
* Part 1, Python: 279 bytes, <100 ms
356-
* Part 2, Python (simple): 646 bytes, ~10 s
357-
* Part 2, Python (optimized): 633 bytes, ~4 s
356+
* Part 2, Python (simple): 614 bytes, ~10 s
357+
* Part 2, Python (optimized): 601 bytes, ~4 s

2018/22/aoc2018_22_part2_try1.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
_=range
2-
import re,collections as C
2+
import re
33
n,k,l=map(int,re.findall('\d+',open("input.txt").read()))
44
w=2*k;h=l+w
55
m=20183;g=[[(x*16807+n)%m for x in _(w+1)]]+[[((y+1)*48271+n)%m]+w*[0]for y in _(h)]
66
for y in _(h):
77
for x in _(w):g[y+1][x+1]=(g[y][x+1]*g[y+1][x]+n)%m
88
g[l][k]=0;g=[[c%3for c in r]for r in g]
9-
d=C.defaultdict(lambda:2000);o=(0,0,1);d[o]=0;o,q={o},set()
9+
d={};o=(0,0,1);d[o]=0;o,q={o},set()
1010
while o or q:
1111
if not o:o,q=q,set()
1212
i=o.pop();u,v,c=i;i=d[i]
@@ -16,5 +16,5 @@
1616
for n in(0,1,2):
1717
if n!=g[y][x]and n!=g[v][u]:
1818
z=(x,y,n);t=i+1+7*(n!=c)
19-
if t<d[z]:d[z]=t;q|={z}
19+
if t<d.get(z,2000):d[z]=t;q|={z}
2020
print min(d[(k,l,1)],d[(k,l,2)]+7)

2018/22/aoc2018_22_part2_try2.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11
_=range
2-
import re,collections as C
2+
import re
33
n,k,l=map(int,re.findall('\d+',open("input.txt").read()))
44
w=2*k;h=l+w
55
m=20183;g=[[(x*16807+n)%m for x in _(w+1)]]+[[((y+1)*48271+n)%m]+w*[0]for y in _(h)]
66
for y in _(h):
77
for x in _(w):g[y+1][x+1]=(g[y][x+1]*g[y+1][x]+n)%m
88
g[l][k]=0;g=[[c%3for c in r]for r in g]
9-
d=C.defaultdict(lambda:2000);o,q={(0,0,1,0)},set()
9+
d={};o,q={(0,0,1,0)},set()
1010
while o or q:
1111
if not o:o,q=q,set()
1212
u,v,c,t=o.pop();z=(u,v,c)
13-
if t<d[z]:
13+
if t<d.get(z,2000):
1414
d[z]=t;q|={(u,v,n,t+7)for n in(0,1,2)if n!=c and n!=g[v][u]}
1515
for a,b in((-1,0),(0,-1),(1,0),(0,1)):
1616
x,y=u+a,v+b

2018/24/README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -359,4 +359,4 @@ Still, the complexity of the task description made me write a non-golf version f
359359
Indices 7 and 8 are reset after every round of the battle.
360360

361361

362-
* Parts 1+2, Python: 865 bytes, ~5 s
362+
* Parts 1+2, Python: 839 bytes, ~5 s

2018/24/aoc2018_24.py

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
_,S=int,sorted
2-
import re,collections as C
2+
import re
33
t,A,B,w=2,[],0,0
44
for l in open("input.txt"):
55
if':'in l:t-=1
66
m=re.match(r'(\d+) u.*h (\d+) h.*s( \((.*)\))? w.*s (\d+) (.*) d.*ve (\d+)',l)
77
if m:
8-
m=m.groups();g=[-_(m[6]),t,_(m[0]),_(m[1]),C.defaultdict(lambda:1),m[5],_(m[4])];A+=[g]
8+
m=m.groups();g=[-_(m[6]),t,_(m[0]),_(m[1]),{},m[5],_(m[4])];A+=[g]
99
if m[3]:
1010
for m in map(str.strip,m[3].split(';')):
1111
for a in m[8+(m[0]<'w'):].split(','):g[4][a.strip()]=2*(m[0]>'i')
@@ -15,10 +15,10 @@
1515
w,m=set(g[1]for g in G),0
1616
if len(w)<2:break
1717
for g in S(G,key=lambda g:(-g[2]*g[6],g[0])):
18-
t=S((-g[2]*g[6]*t[4][g[5]],-t[2]*t[6],t[0],t)for t in G if(t[1]-g[1])*t[8])
18+
t=S((-g[2]*g[6]*t[4].get(g[5],1),-t[2]*t[6],t[0],t)for t in G if(t[1]-g[1])*t[8])
1919
if t and t[0][0]:t=t[0];g[7]=t[3];g[7][8]=0;m=1
2020
for g in S(G):
21-
if g[7]:t=g[7];t[2]=max(0,t[2]-g[2]*g[6]*t[4][g[5]]/t[3])
21+
if g[7]:t=g[7];t[2]=max(0,t[2]-g[2]*g[6]*t[4].get(g[5],1)/t[3])
2222
G=[g[:7]+[0,1]for g in G if g[2]>0]
2323
w=w=={1};B+=1
2424
if(B<2)+w:print sum(g[2]for g in G)

2019/06/README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -124,4 +124,4 @@ Your puzzle answer was `484`.
124124
Some classic operations on an directed acyclic graph (DAG), a.k.a. trees. The important trick for the second part is to find the "common ancestor" of the `YOU` and `SAN` nodes and then just add the subgraph depths together.
125125

126126
* Part 1, Python: 113 bytes, <100 ms
127-
* Part 2, Python: 168 bytes, <100 ms
127+
* Part 2, Python: 165 bytes, <100 ms

2019/09/README.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -60,5 +60,5 @@ With this, the Intcode machine gets a proper stack, and the program of part 2 ma
6060

6161
The golf implementations are almost identical, only the input parameter changes.
6262

63-
* Part 1, Python: 440 bytes, <100 ms
64-
* Part 2, Python: 440 bytes, ~2.5 s
63+
* Part 1, Python: 418 bytes, <100 ms
64+
* Part 2, Python: 418 bytes, ~2.5 s

2019/09/aoc2019_09_part1.py

+2-4
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
1-
from collections import*
2-
_=int
3-
M=defaultdict(_,enumerate(map(_,open("input.txt").read().split(','))));p=s=0
1+
M=dict(enumerate(map(int,open("input.txt").read().split(','))));p=s=0
42
while M[p]!=99:
5-
o=M[p];l=map(_,str(o)[-3::-1]+"000");o%=100;n=_("0331122331"[o]);i,j,k=[M[p+x]+s*(m>1)for x,m in zip((1,2,3),l)];a,b=[(M[x]if m-1else x)for x,m in zip((i,j),l)];p+=n+1
3+
o=M[p];l=map(int,str(o)[-3::-1]+"000");o%=100;n=int("0331122331"[o]);i,j,k=[M.get(p+x,0)+s*(m>1)for x,m in zip((1,2,3),l)];a,b=[(M.get(x,0)if m-1else x)for x,m in zip((i,j),l)];p+=n+1
64
if o<2:M[k]=a+b
75
elif o<3:M[k]=a*b
86
elif o<4:M[i]=1

2019/09/aoc2019_09_part2.py

+2-4
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
1-
from collections import*
2-
_=int
3-
M=defaultdict(_,enumerate(map(_,open("input.txt").read().split(','))));p=s=0
1+
M=dict(enumerate(map(int,open("input.txt").read().split(','))));p=s=0
42
while M[p]!=99:
5-
o=M[p];l=map(_,str(o)[-3::-1]+"000");o%=100;n=_("0331122331"[o]);i,j,k=[M[p+x]+s*(m>1)for x,m in zip((1,2,3),l)];a,b=[(M[x]if m-1else x)for x,m in zip((i,j),l)];p+=n+1
3+
o=M[p];l=map(int,str(o)[-3::-1]+"000");o%=100;n=int("0331122331"[o]);i,j,k=[M.get(p+x,0)+s*(m>1)for x,m in zip((1,2,3),l)];a,b=[(M.get(x,0)if m-1else x)for x,m in zip((i,j),l)];p+=n+1
64
if o<2:M[k]=a+b
75
elif o<3:M[k]=a*b
86
elif o<4:M[i]=2

2019/11/README.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -87,5 +87,5 @@ Your puzzle answer was `JZPJRAGJ`.
8787

8888
This puzzle puts the Intcode computer into "practical" use, and it's quite a fun thing indeed. The program of part 1 simply performs a few thousand iterations of a [Turmite](https://en.wikipedia.org/wiki/Turmite)-style cellular automaton; part 2 uses a rather complex algorithm to produce a simple 40x6-pixel bitmap.
8989

90-
* Part 1, Python: 521 bytes, ~500 ms
91-
* Part 2, Python: 583 bytes, ~100 ms
90+
* Part 1, Python: 499 bytes, ~500 ms
91+
* Part 2, Python: 561 bytes, ~100 ms

2019/11/aoc2019_11_part1.py

+3-4
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
1-
from collections import*
2-
_,G,z,r,d=int,{},1,0,-1j
3-
M=defaultdict(_,enumerate(map(_,open("input.txt").read().split(','))));p=s=0
1+
G,z,r,d={},1,0,-1j
2+
M=dict(enumerate(map(int,open("input.txt").read().split(','))));p=s=0
43
while M[p]!=99:
5-
o=M[p];l=map(_,str(o)[-3::-1]+"000");o%=100;n=_("0331122331"[o]);i,j,k=[M[p+x]+s*(m>1)for x,m in zip((1,2,3),l)];a,b=[(M[x]if m-1else x)for x,m in zip((i,j),l)];p+=n+1
4+
o=M[p];l=map(int,str(o)[-3::-1]+"000");o%=100;n=int("0331122331"[o]);i,j,k=[M.get(p+x,0)+s*(m>1)for x,m in zip((1,2,3),l)];a,b=[(M.get(x,0)if m-1else x)for x,m in zip((i,j),l)];p+=n+1
65
if o<2:M[k]=a+b
76
elif o<3:M[k]=a*b
87
elif o<4:M[i]=G.get(r,0)

2019/11/aoc2019_11_part2.py

+3-4
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
1-
from collections import*
2-
_,G,z,r,d=int,{0:1},1,0,-1j
3-
M=defaultdict(_,enumerate(map(_,open("input.txt").read().split(','))));p=s=0
1+
G,z,r,d={0:1},1,0,-1j
2+
M=dict(enumerate(map(int,open("input.txt").read().split(','))));p=s=0
43
while M[p]!=99:
5-
o=M[p];l=map(_,str(o)[-3::-1]+"000");o%=100;n=_("0331122331"[o]);i,j,k=[M[p+x]+s*(m>1)for x,m in zip((1,2,3),l)];a,b=[(M[x]if m-1else x)for x,m in zip((i,j),l)];p+=n+1
4+
o=M[p];l=map(int,str(o)[-3::-1]+"000");o%=100;n=int("0331122331"[o]);i,j,k=[M.get(p+x,0)+s*(m>1)for x,m in zip((1,2,3),l)];a,b=[(M.get(x,0)if m-1else x)for x,m in zip((i,j),l)];p+=n+1
65
if o<2:M[k]=a+b
76
elif o<3:M[k]=a*b
87
elif o<4:M[i]=G.get(r,0)

2019/13/README.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -49,5 +49,5 @@ The non-golf implementation contains a console visualization:
4949

5050
./intcode.py 13.2-vis
5151

52-
* Part 1, Python: 454 bytes, ~100 ms
53-
* Part 2, Python: 539 bytes, ~3 s
52+
* Part 1, Python: 432 bytes, ~100 ms
53+
* Part 2, Python: 517 bytes, ~3 s

2019/13/aoc2019_13_part1.py

+3-4
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
1-
from collections import*
2-
_=int;q=z=0
3-
M=defaultdict(_,enumerate(map(_,open("input.txt").read().split(','))));p=s=0
1+
q=z=0
2+
M=dict(enumerate(map(int,open("input.txt").read().split(','))));p=s=0
43
while M[p]!=99:
5-
o=M[p];l=map(_,str(o)[-3::-1]+"000");o%=100;n=_("0331122331"[o]);i,j,k=[M[p+x]+s*(m>1)for x,m in zip((1,2,3),l)];a,b=[(M[x]if m-1else x)for x,m in zip((i,j),l)];p+=n+1
4+
o=M[p];l=map(int,str(o)[-3::-1]+"000");o%=100;n=int("0331122331"[o]);i,j,k=[M.get(p+x,0)+s*(m>1)for x,m in zip((1,2,3),l)];a,b=[(M.get(x,0)if m-1else x)for x,m in zip((i,j),l)];p+=n+1
65
if o<2:M[k]=a+b
76
elif o<3:M[k]=a*b
87
elif o<5:q=(q+1)%3;z+=q<1and a==2

2019/13/aoc2019_13_part2.py

+3-4
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
1-
from collections import*
2-
_,q,w,z=int,[],{},{}
3-
M=defaultdict(_,enumerate(map(_,open("input.txt").read().split(','))));p=s=0
1+
q,w,z=[],{},{}
2+
M=dict(enumerate(map(int,open("input.txt").read().split(','))));p=s=0
43
M[0]=2
54
while M[p]!=99:
6-
o=M[p];l=map(_,str(o)[-3::-1]+"000");o%=100;n=_("0331122331"[o]);i,j,k=[M[p+x]+s*(m>1)for x,m in zip((1,2,3),l)];a,b=[(M[x]if m-1else x)for x,m in zip((i,j),l)];p+=n+1
5+
o=M[p];l=map(int,str(o)[-3::-1]+"000");o%=100;n=int("0331122331"[o]);i,j,k=[M.get(p+x,0)+s*(m>1)for x,m in zip((1,2,3),l)];a,b=[(M.get(x,0)if m-1else x)for x,m in zip((i,j),l)];p+=n+1
76
if o<2:M[k]=a+b
87
elif o<3:M[k]=a*b
98
elif o<4:M[i]=(z[3]<z[4])-(z[3]>z[4])

2019/15/README.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -151,5 +151,5 @@ I say "properly implemented", because my initial implementation was *not* perfec
151151

152152
While recoding the solution in golf form, I fixed my DFS bug and don't require a BFS for part 1 any longer. Moreover, I removed the "relative base" functionality from the Intcode interpreter, as it's not used by the program.
153153

154-
* Part 1, Python: 687 bytes, ~300 ms
155-
* Part 2, Python: 795 bytes, ~300 ms
154+
* Part 1, Python: 665 bytes, ~300 ms
155+
* Part 2, Python: 773 bytes, ~300 ms

2019/15/aoc2019_15_part1.py

+2-4
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,9 @@
1-
from collections import*
2-
_=int
3-
M=defaultdict(_,enumerate(map(_,open("input.txt").read().split(','))))
1+
M=dict(enumerate(map(int,open("input.txt").read().split(','))))
42
D,R,G,L,P=[0,-1j,1j,-1,1],[0,2,1,4,3],{0:2},0,[0]
53
def W(d):
64
global L,P;L+=D[d];p=r=0
75
while r<1:
8-
o=M[p];l=map(_,str(o)[-3::-1]+"000");o%=100;n=_("0331122331"[o]);i,j,k=[M[p+x]for x,m in zip((1,2,3),l)];a,b=[(M[x]if m-1else x)for x,m in zip((i,j),l)];p+=n+1
6+
o=M[p];l=map(int,str(o)[-3::-1]+"000");o%=100;n=int("0331122331"[o]);i,j,k=[M.get(p+x,0)for x,m in zip((1,2,3),l)];a,b=[(M.get(x,0)if m-1else x)for x,m in zip((i,j),l)];p+=n+1
97
if o<2:M[k]=a+b
108
elif o<3:M[k]=a*b
119
elif o<4:M[i]=d

2019/15/aoc2019_15_part2.py

+2-4
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,9 @@
1-
from collections import*
2-
_=int
3-
M=defaultdict(_,enumerate(map(_,open("input.txt").read().split(','))))
1+
M=dict(enumerate(map(int,open("input.txt").read().split(','))))
42
D,R,G,L,P=[0,-1j,1j,-1,1],[0,2,1,4,3],{0:2},0,[0]
53
def W(d):
64
global L,T,P;L+=D[d];p=r=0
75
while r<1:
8-
o=M[p];l=map(_,str(o)[-3::-1]+"000");o%=100;n=_("0331122331"[o]);i,j,k=[M[p+x]for x,m in zip((1,2,3),l)];a,b=[(M[x]if m-1else x)for x,m in zip((i,j),l)];p+=n+1
6+
o=M[p];l=map(int,str(o)[-3::-1]+"000");o%=100;n=int("0331122331"[o]);i,j,k=[M.get(p+x,0)for x,m in zip((1,2,3),l)];a,b=[(M.get(x,0)if m-1else x)for x,m in zip((i,j),l)];p+=n+1
97
if o<2:M[k]=a+b
108
elif o<3:M[k]=a*b
119
elif o<4:M[i]=d

2019/17/README.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -150,5 +150,5 @@ Part 2 is where the meat is. Fortunately, the inputs are constructed in a way th
150150

151151
All this adds up to a significant amount of code that's not very amenable to golfing, hence I ended up with well above a kilobyte for part 2 (including the Intcode interpreter).
152152

153-
* Part 1, Python: 568 bytes, ~250 ms
154-
* Part 2, Python: 1150 bytes, ~500 ms
153+
* Part 1, Python: 546 bytes, ~250 ms
154+
* Part 2, Python: 1128 bytes, ~500 ms

2019/17/aoc2019_17_part1.py

+3-4
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
1-
from collections import*
2-
_=int;G=""
3-
M=defaultdict(_,enumerate(map(_,open("input.txt").read().split(','))));p=s=0
1+
G=""
2+
M=dict(enumerate(map(int,open("input.txt").read().split(','))));p=s=0
43
while M[p]!=99:
5-
o=M[p];l=map(_,str(o)[-3::-1]+"000");o%=100;n=_("0331122331"[o]);i,j,k=[M[p+x]+s*(m>1)for x,m in zip((1,2,3),l)];a,b=[(M[x]if m-1else x)for x,m in zip((i,j),l)];p+=n+1
4+
o=M[p];l=map(int,str(o)[-3::-1]+"000");o%=100;n=int("0331122331"[o]);i,j,k=[M.get(p+x,0)+s*(m>1)for x,m in zip((1,2,3),l)];a,b=[(M.get(x,0)if m-1else x)for x,m in zip((i,j),l)];p+=n+1
65
if o<2:M[k]=a+b
76
elif o<3:M[k]=a*b
87
elif o<5:G+=chr(a)

2019/17/aoc2019_17_part2.py

+3-4
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
1-
from collections import*
2-
_,E,L=int,enumerate,len
3-
M=defaultdict(_,E(map(_,open("input.txt").read().split(','))));p=s=0;M[0]=2
1+
E,L=enumerate,len
2+
M=dict(E(map(int,open("input.txt").read().split(','))));p=s=0;M[0]=2
43
def R(I):
54
global p,s;q=[]
65
while M[p]!=99:
7-
o=M[p];l=map(_,str(o)[-3::-1]+"000");o%=100;n=_("0331122331"[o]);i,j,k=[M[p+x]+s*(m>1)for x,m in zip((1,2,3),l)];a,b=[(M[x]if m-1else x)for x,m in zip((i,j),l)];p+=n+1
6+
o=M[p];l=map(int,str(o)[-3::-1]+"000");o%=100;n=int("0331122331"[o]);i,j,k=[M.get(p+x,0)+s*(m>1)for x,m in zip((1,2,3),l)];a,b=[(M.get(x,0)if m-1else x)for x,m in zip((i,j),l)];p+=n+1
87
if o<2:M[k]=a+b
98
elif o<3:M[k]=a*b
109
elif o<4:

PythonCodeGolfHints.md

+9-3
Original file line numberDiff line numberDiff line change
@@ -110,10 +110,10 @@ When importing from modules with short names (like `re`), it's usually best to u
110110
import re
111111
N=[map(int,re.findall('-?\d+',l)for l in open("input.txt")]
112112

113-
This is optimal unless the number of calls to this module's functions gets too large or the module name gets too long. The latter is typically the case for the very useful `itertools` or `collections`, in which case just importing all functions into the global namespace works best:
113+
This is optimal unless the number of calls to this module's functions gets too large or the module name gets too long. The latter is typically the case for the very useful `itertools`, in which case just importing all functions into the global namespace works best:
114114

115-
from collections import*
116-
x=defaultdict(int)
115+
from itertools import*
116+
for p in product(A,B,C):[...]
117117

118118
(Note the missing whitespace after `import`; it's simply not needed!)
119119

@@ -186,6 +186,12 @@ Sometimes a loop with an empty body is required. Instead of using `pass` as inte
186186

187187

188188

189+
## Don't use `defaultdict`
190+
191+
There's no denying that the `defaultdict` class in the `collections` module is genuinely useful. However, it comes at a high cost, because the identifiers are awkwardly long. As long as the `defaultdict` is only used to provide immutable default values (like integers or strings), it's often shorter to just use the `.get()` method with a suitable default when reading. More than 4 or 5 of such accesses (depending on context) are required to make the import and use of `defaultdict` worthwhile.
192+
193+
194+
189195
## Use arithmetic as logic
190196

191197
Pythons `and`, `or` and `not` operators are quite expensive in terms of code size; not only are they quite long themselves, in most cases they require at least one additional whitespace around them. However, boolean expressions like comparion results are freely convertible into integers in Python, which makes it possible to emulate the effect of `and`/`or`/`not` with `*`/`+`/`^`:

0 commit comments

Comments
 (0)