-
Notifications
You must be signed in to change notification settings - Fork 0
/
day10.py
executable file
·134 lines (89 loc) · 3.35 KB
/
day10.py
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
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
#!/usr/bin/env python3
import re
import aoc
from aoc import Coord
class StarData:
def __init__( self, coord, velocity ):
self.coord = coord
self.vel = velocity
def __str__( self ):
return "(%s,%s)" % ( self.coord, self.vel )
def __repr__( self ):
return "(%s,%s)" % ( self.coord, self.vel )
def parse_input( input_list ):
# Map of velocitys keyed by coordinate.
data = list()
# Example input data
# position=< 9, 1> velocity=< 0, 2>
regex = r'position=<\s*(-?\d+),\s*(-?\d+)> velocity=<\s*(-?\d+),\s*(-?\d+)>'
for line in input_list:
match_obj = re.search( regex, line )
assert match_obj
coord = Coord( int( match_obj.group( 1 ) ), int( match_obj.group( 2 ) ) )
vel = Coord( int( match_obj.group( 3 ) ), int( match_obj.group( 4 ) ) )
data.append( StarData( coord, vel ) )
return data
def draw( data ):
min_bound, max_bound = calc_bound( data )
stars = set()
for star_data in data:
stars.add( star_data.coord )
output = ''
for y_val in range( min_bound.y_val, max_bound.y_val + 1 ):
for x_val in range( min_bound.x_val, max_bound.x_val + 1 ):
if ( x_val, y_val ) in stars:
output += '#'
else:
output += '.'
if y_val != max_bound.y_val:
output += '\n'
return output
def move_stars( data ):
for star in data:
star.coord = Coord( star.coord.x_val + star.vel.x_val, star.coord.y_val + star.vel.y_val )
def calc_bound( data ):
coord = data[0].coord
x_min = x_max = coord.x_val
y_min = y_max = coord.y_val
for star_data in data:
x_min = min( x_min, star_data.coord.x_val )
x_max = max( x_max, star_data.coord.x_val )
y_min = min( y_min, star_data.coord.y_val )
y_max = max( y_max, star_data.coord.y_val )
return Coord( x_min, y_min ), Coord( x_max, y_max )
def calc_area( min_coord, max_coord ):
area = ( max_coord.x_val - min_coord.x_val + 1 ) * ( max_coord.y_val - min_coord.y_val + 1 )
return area
def simulate( input_list, time_to_simulate = -1 ):
data = parse_input( input_list )
seconds = 0
min_bound, max_bound = calc_bound( data )
area = calc_area( min_bound, max_bound )
# Simulate until the area stars gets bigger or for the amount of time
# passed in. Unfortuately, when we figure out that we are one past the
# correct time, we don't have the previous frame anymore. It is actually
# faster to resimulate then it is to save the previous frame each iteration
# so the caller needs to call this twice to if the output is needed.
while time_to_simulate:
time_to_simulate -= 1
move_stars( data )
min_bound, max_bound = calc_bound( data )
new_area = calc_area( min_bound, max_bound )
if new_area > area:
break
seconds += 1
area = new_area
output = draw( data )
return output, seconds
def part1( input_list ):
# Find out how long we need to simulate.
_, seconds = simulate( input_list )
# Resimulate to get the correct output.
output, _ = simulate( input_list, seconds )
#print( output )
return output
def part2( input_list ):
_, seconds = simulate( input_list )
return seconds
if __name__ == "__main__":
aoc.main( part1, part2 )