summaryrefslogtreecommitdiff
path: root/2024/aoc2024-d20.py
blob: 16ed3c4b50c41c79105070b39caad4a117102459 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
#advent of code 2024
#day 20
#shamelessly copypasted previous pathfinding and input parsing
#except it needed much adjustments because it's not really pathfinding
#basically: calculate map of distances between each point with djikstra
#since the path never branches, you can use these distances 
#instead of recalculating the path after each cheat
#cheat 

grid = {}; 
xMin, yMin, xMax, yMax = 0,0,0,0; #could get rid of it but w/e
dirs = [(1,0),(0,1),(-1,0),(0,-1)]; #east, south, west, north

f = open("20.in","r");
for y,l in enumerate(f):
	yMax = max(y,yMax);
	for x,c in enumerate(l.strip()):
		if c == "S": 
			start = (x,y);
			c = "."
		elif c == "E": 
			end = (x,y);
			c = "."
		grid[(x,y)]=c;
		xMax = max(xMax,x);
f.close();

def getAdjacent(coordinates):
	adj = [];
	xp, yp = coordinates;
	for d in dirs:
		dx,dy = d;
		if grid.get((xp+dx,yp+dy),"#") != "#": 
			adj.append((xp+dx,yp+dy));
	return adj;

def djikstra(startpos,endpos):
	queue = [];
	DistanceMap = {};
	queue = [(startpos,0)];
	while queue:
		coords,dist = queue.pop();
		if coords in DistanceMap: continue;
		DistanceMap[coords] = min(DistanceMap.get(coords,float('inf')),dist);
		for NextPos in getAdjacent(coords):
			queue.append((NextPos,dist+1));
	return DistanceMap;

def cheatAdjacent(coordinates,secs):
	adj = set();
	px,py = coordinates;
	for X in range(secs+1):
		for Y in range(secs+1-X):
			adj.add((px+X*1,py+Y*1));
			adj.add((px+X*(-1),py+Y*(-1)));
			adj.add((px+X*(1),py+Y*(-1)));
			adj.add((px+X*(-1),py+Y*(1)));
	return adj;

PathDistances = djikstra(start,end);
part1 = 0;
part2 = 0;
for position in PathDistances:
	d1 = PathDistances.get(position,-1); #negative value if there's no match
	CheatedSteps = cheatAdjacent(position,20);
	for ch in CheatedSteps:
		d2 = PathDistances.get(ch,-1); #negative value if there's no match
		if d2 == -1: continue; #if the step isn't in the PathDistances, then it's not valid
		manhattan = abs(ch[0]-position[0]) + abs(ch[1]-position[1])
		ScoreDifference = d2-d1 - manhattan
		if ScoreDifference >= 100: #from description, doesn't work for example
			part2 += 1;
			part1 += 1*(manhattan <= 2);

print("part 1 =", part1);
print("part 2 =", part2); 
#grid print for reference/debugging
#for y in range(yMax+1):
#	for x in range(xMax+1):
#		c = grid[(x,y)];
#		if (x,y) == start: c = "S";
#		elif (x,y) == end: c = "E";		
#		print(c, end="");
#	print();