@@ -177,6 +177,21 @@ int main()
177177 throw std::runtime_error (" pe_synth failed: " + std::string (reinterpret_cast <char const *>(err.message .data ()), err.message .size ()));
178178 }
179179
180+ // Ensure `$random` lowered to a PE RNG macro (otherwise it may constant-fold and always spawn I).
181+ {
182+ bool has_rng{};
183+ for (auto & blk : nl.models )
184+ {
185+ for (auto * m = blk.begin ; m != blk.curr ; ++m)
186+ {
187+ if (m->type != ::phy_engine::model::model_type::normal) { continue ; }
188+ if (m->ptr == nullptr ) { continue ; }
189+ if (m->ptr ->get_model_name () == ::fast_io::u8string_view{u8" RANDOM_GENERATOR4" }) { has_rng = true ; }
190+ }
191+ }
192+ if (!has_rng) { return 12 ; }
193+ }
194+
180195 if (!c.analyze ()) { return 12 ; }
181196
182197 auto * in_clk = input_by_name.at (" clk" );
@@ -244,21 +259,70 @@ int main()
244259 if (read_row (y) != 0 ) { return 15 ; }
245260 }
246261
247- // 2) Rotate should rotate the first I piece in-place (no fall due to priority).
262+ // 2) Move right once, then rotate to place a vertical obstacle column at x=2.
263+ set_in (in_right, true );
264+ set_in (in_clk, false );
265+ c.digital_clk ();
266+ tick ();
267+ set_in (in_right, false );
268+ set_in (in_clk, false );
269+ c.digital_clk ();
270+ if (read_port_bit (*game_over_port)) { return 16 ; }
271+ if (read_row (0 ) != 0b111100 ) { return 17 ; } // I moved right (px=2)
272+
248273 set_in (in_rotate, true );
249274 set_in (in_clk, false );
250275 c.digital_clk ();
251276 tick ();
252277 set_in (in_rotate, false );
253278 set_in (in_clk, false );
254279 c.digital_clk ();
255- if (read_port_bit (*game_over_port)) { return 16 ; }
256- if (read_row (0 ) != 0b000010 ) { return 17 ; }
257- if (read_row (1 ) != 0b000010 ) { return 18 ; }
258- if (read_row (2 ) != 0b000010 ) { return 19 ; }
259- if (read_row (3 ) != 0b000010 ) { return 20 ; }
280+ if (read_port_bit (*game_over_port)) { return 18 ; }
281+ if (read_row (0 ) != 0b000100 ) { return 19 ; }
282+ if (read_row (1 ) != 0b000100 ) { return 20 ; }
283+ if (read_row (2 ) != 0b000100 ) { return 21 ; }
284+ if (read_row (3 ) != 0b000100 ) { return 22 ; }
285+
286+ // 3) Let the vertical I fall and lock at the bottom (obstacle at rows2..5, x=2).
287+ set_in (in_left, false );
288+ set_in (in_right, false );
289+ set_in (in_rotate, false );
290+ tick (); // py=1
291+ tick (); // py=2
292+ tick (); // lock -> CLEAR
293+
294+ if (read_row (0 ) != 0 ) { return 23 ; }
295+ if (read_row (1 ) != 0 ) { return 24 ; }
296+ if (read_row (2 ) != 0b000100 ) { return 25 ; }
297+ if (read_row (3 ) != 0b000100 ) { return 26 ; }
298+ if (read_row (4 ) != 0b000100 ) { return 27 ; }
299+ if (read_row (5 ) != 0b000100 ) { return 28 ; }
300+
301+ // 4) Spawn one more piece and ensure it does not overlap ("phase") into the obstacle column.
302+ // (All pieces overlap bit2 at spawn, so collide_down should stop them above row2.)
303+ {
304+ bool saw_spawn{};
305+ for (std::size_t i{}; i < 256 ; ++i)
306+ {
307+ tick ();
308+ if (read_port_bit (*game_over_port)) { return 29 ; }
309+ if (read_row (0 ) != 0 )
310+ {
311+ saw_spawn = true ;
312+ break ;
313+ }
314+ }
315+ if (!saw_spawn) { return 30 ; }
316+
317+ tick (); // py=1
318+ tick (); // collide_down -> lock
319+ if (read_row (2 ) != 0b000100 ) { return 31 ; }
320+ if (read_row (3 ) != 0b000100 ) { return 32 ; }
321+ if (read_row (4 ) != 0b000100 ) { return 33 ; }
322+ if (read_row (5 ) != 0b000100 ) { return 34 ; }
323+ }
260324
261- // 3 ) Run until game_over and check the "X" overlay.
325+ // 5 ) Run until game_over and check the "X" overlay.
262326 set_in (in_left, false );
263327 set_in (in_rotate, false );
264328 set_in (in_right, true ); // bias towards a quick loss
@@ -273,14 +337,14 @@ int main()
273337 break ;
274338 }
275339 }
276- if (!saw_game_over) { return 21 ; }
277-
278- if (read_row (0 ) != 0b100001 ) { return 22 ; }
279- if (read_row (1 ) != 0b010010 ) { return 23 ; }
280- if (read_row (2 ) != 0b001100 ) { return 24 ; }
281- if (read_row (3 ) != 0b001100 ) { return 25 ; }
282- if (read_row (4 ) != 0b010010 ) { return 26 ; }
283- if (read_row (5 ) != 0b100001 ) { return 27 ; }
340+ if (!saw_game_over) { return 36 ; }
341+
342+ if (read_row (0 ) != 0b100001 ) { return 37 ; }
343+ if (read_row (1 ) != 0b010010 ) { return 38 ; }
344+ if (read_row (2 ) != 0b001100 ) { return 39 ; }
345+ if (read_row (3 ) != 0b001100 ) { return 40 ; }
346+ if (read_row (4 ) != 0b010010 ) { return 41 ; }
347+ if (read_row (5 ) != 0b100001 ) { return 42 ; }
284348
285349 // 4) Gate count check (after passing the sim checks), under O4 optimization.
286350 {
0 commit comments