1
+ from collections import defaultdict
2
+
3
+ import numpy as np
4
+ from tqdm import tqdm
5
+
6
+ from utils .read_txt_data import txt_to_str
7
+
8
+ class Env :
9
+ def __init__ (self ):
10
+ jet_str = txt_to_str ("data/17.txt" )
11
+ self .jet = list (jet_str )
12
+ self .jet = [- 1 if x == "<" else 1 for x in self .jet ]
13
+ self .step = 0
14
+ self .real_step = 0
15
+ self .rock_idx = 0
16
+ self .settled = {}
17
+ self .active_rock = None
18
+ self .error = False
19
+
20
+ def get_current_height (self ):
21
+ if len (self .settled ) == 0 :
22
+ highest = - 1
23
+ else :
24
+ highest = max (self .settled , key = lambda x : x [1 ])[1 ]
25
+ return highest
26
+ def simulate_rock (self ):
27
+ # create rock
28
+ highest = self .get_current_height ()
29
+ self .active_rock = Rock (self .rock_idx , y_offset = highest + 4 )
30
+ while True :
31
+ # sidewards mov
32
+ current_jet = self .jet [self .step ]
33
+ self .step = (self .step + 1 ) % len (self .jet )
34
+ self .real_step += 1
35
+ rel_mov = [current_jet , 0 ]
36
+ self .active_rock .move (rel_mov , self .settled )
37
+ # downwards mov
38
+ rel_mov = [0 , - 1 ]
39
+ should_settle = not self .active_rock .move (rel_mov , self .settled )
40
+ if should_settle :
41
+ if self .step > 1000 and self .active_rock .tiles [0 ][1 ] < 10 :
42
+ self .error = True
43
+ for tiles in self .active_rock .tiles :
44
+ self .settled [tuple (tiles )] = 1
45
+ # heuristic: remove lower parts
46
+ self .settled = {t : 1 for t in self .settled if t [1 ] >= highest - 30 }
47
+ break
48
+ self .rock_idx = (self .rock_idx + 1 ) % 5
49
+
50
+ def visualize_settled (self ):
51
+ min_y = min (self .settled , key = lambda x : x [1 ])[1 ]
52
+ max_y = self .get_current_height () + 5
53
+ screen = np .zeros ((max_y - min_y , 7 ))
54
+ for t in self .settled :
55
+ screen [- (t [1 ] - min_y ) - 1 , t [0 ]] = 1
56
+ for row in screen :
57
+ row_str = "|"
58
+ for char in row :
59
+ row_str += "." if char == 0 else "#"
60
+ print (row_str + "|" )
61
+ print ("-----------------------------------------------------------" )
62
+
63
+ class Rock :
64
+ def __init__ (self , idx , y_offset ):
65
+ if idx == 0 :
66
+ self .tiles = [
67
+ [2 , y_offset ], [3 , y_offset ], [4 , y_offset ], [5 , y_offset ]
68
+ ]
69
+ elif idx == 1 :
70
+ self .tiles = [
71
+ [3 , y_offset ], [2 , y_offset + 1 ], [3 , y_offset + 1 ], [4 , y_offset + 1 ], [3 , y_offset + 2 ]
72
+ ]
73
+ elif idx == 2 :
74
+ self .tiles = [
75
+ [2 , y_offset ], [3 , y_offset ], [4 , y_offset ], [4 , y_offset + 1 ], [4 , y_offset + 2 ]
76
+ ]
77
+ elif idx == 3 :
78
+ self .tiles = [
79
+ [2 , y_offset ], [2 , y_offset + 1 ], [2 , y_offset + 2 ], [2 , y_offset + 3 ]
80
+ ]
81
+ elif idx == 4 :
82
+ self .tiles = [
83
+ [2 , y_offset ], [3 , y_offset ], [2 , y_offset + 1 ], [3 , y_offset + 1 ]
84
+ ]
85
+ else :
86
+ raise ValueError ()
87
+
88
+ def move (self , rel_mov , settled ):
89
+ falling = rel_mov [0 ] == 0
90
+ new_tiles = [[t [0 ] + rel_mov [0 ], t [1 ] + rel_mov [1 ]] for t in self .tiles ]
91
+ # check for collision
92
+ for t in new_tiles :
93
+ # boarders
94
+ if falling :
95
+ if t [1 ] < 0 :
96
+ return False
97
+ else :
98
+ if t [0 ] < 0 or t [0 ] > 6 :
99
+ return False
100
+
101
+ if tuple (t ) in settled :
102
+ return False
103
+ # all checks passed
104
+ self .tiles = new_tiles
105
+ return True
106
+
107
+
108
+
109
+ def first ():
110
+ env = Env ()
111
+ for i in range (2022 ):
112
+ env .simulate_rock ()
113
+ env .visualize_settled ()
114
+ print (env .get_current_height () + 1 )
115
+
116
+
117
+ def get_chosen_step ():
118
+ env = Env ()
119
+ step_at_0 = defaultdict (lambda : 0 )
120
+ for i in tqdm (range (1000000 )):
121
+ if i % 5 == 0 :
122
+ step_at_0 [env .step ] += 1
123
+ env .simulate_rock ()
124
+ env .visualize_settled ()
125
+ print (step_at_0 )
126
+ chosen_step = max (step_at_0 , key = lambda x : step_at_0 [x ])
127
+ print (chosen_step , step_at_0 [chosen_step ])
128
+ print (env .error )
129
+
130
+
131
+ def get_height (num_rocks ):
132
+ rock_offset = 3460
133
+ height_offset = 5446
134
+ rock_period = 1725
135
+ height_inc = 2709
136
+ rest_values = []
137
+ env = Env ()
138
+ for i in range (3460 ):
139
+ env .simulate_rock ()
140
+
141
+ for i in range (1725 ):
142
+ rest_values .append (env .get_current_height () + 1 - height_offset )
143
+ env .simulate_rock ()
144
+
145
+
146
+ if num_rocks < 3460 :
147
+ return None
148
+ num_periods = (num_rocks - rock_offset ) // rock_period
149
+ height = height_offset + num_periods * height_inc
150
+ remaining_rocks = (num_rocks - rock_offset ) % rock_period
151
+ height += rest_values [remaining_rocks ]
152
+ return height
153
+
154
+
155
+ def second ():
156
+ num_rocks = 1000000000000
157
+ print (get_height (num_rocks ))
158
+ # env = Env()
159
+ # for i in range(num_rocks):
160
+ # env.simulate_rock()
161
+ # print(env.get_current_height() + 1)
162
+
163
+
164
+ # # get_chosen_step()
165
+ # cycles = []
166
+ # chosen_step = 80
167
+ # env = Env()
168
+ # for i in tqdm(range(10000)):
169
+ #
170
+ # if i % 5 == 0:
171
+ # if env.step == chosen_step:
172
+ # cycles.append((i, env.real_step, env.get_current_height() + 1))
173
+ # env.simulate_rock()
174
+ # print(cycles[2], cycles[3],cycles[4])
175
+ # print("stop")
176
+
177
+
178
+
179
+
180
+ if __name__ == "__main__" :
181
+ # first()
182
+ second ()
0 commit comments