@@ -107,10 +107,15 @@ fn get_all_puzzles(draft: bool) -> Vec<(&'static str, fn() -> (Puzzle, Board))>
107107 "20_glider_migration" ,
108108 create_glider_migration_puzzle_and_solution,
109109 ) ,
110+ ( "21_four_blinkers" , create_four_blinkers_puzzle_and_solution) ,
110111 ] ;
111112
112113 if draft {
113- puzzles. push ( ( "21_robot_face" , create_robot_face_puzzle_and_solution) ) ;
114+ puzzles. push ( (
115+ "21_glider_collision" ,
116+ create_glider_collision_puzzle_and_solution,
117+ ) ) ;
118+ puzzles. push ( ( "22_robot_face" , create_robot_face_puzzle_and_solution) ) ;
114119 }
115120 puzzles
116121}
@@ -576,6 +581,63 @@ fn create_clock_puzzle_and_solution() -> (Puzzle, Board) {
576581 ( puzzle, initial_board)
577582}
578583
584+ fn create_four_blinkers_puzzle_and_solution ( ) -> ( Puzzle , Board ) {
585+ let size = 16 ;
586+ let offset = size / 2 - 1 ;
587+ // Define the initial board.
588+ let initial_board = Board :: with_live_cells (
589+ size,
590+ vec ! [
591+ Position {
592+ x: offset,
593+ y: offset - 1 ,
594+ } ,
595+ Position {
596+ x: offset - 2 ,
597+ y: offset,
598+ } ,
599+ Position {
600+ x: offset - 1 ,
601+ y: offset,
602+ } ,
603+ Position {
604+ x: offset + 1 ,
605+ y: offset,
606+ } ,
607+ Position {
608+ x: offset + 2 ,
609+ y: offset,
610+ } ,
611+ Position {
612+ x: offset,
613+ y: offset + 1 ,
614+ } ,
615+ ] ,
616+ ) ;
617+ let mut initial_conditions = initial_board. to_exactly_matching_conditions ( ) ;
618+ // Drop a point to force a lucky guess.
619+ initial_conditions. remove ( 3 ) ;
620+ initial_conditions. remove ( 0 ) ;
621+
622+ // Define the final board.
623+ let final_board = initial_board. advance ( 10 ) ;
624+ let final_conditions = final_board. to_exactly_matching_conditions ( ) ;
625+
626+ let puzzle = Puzzle {
627+ title : "Four blinkers" . to_string ( ) ,
628+ summary : "Create four blinkers from very few cells" . to_string ( ) ,
629+ difficulty : Difficulty :: Easy ,
630+ size,
631+ minimal_steps : 10 ,
632+ maximal_steps : 10 ,
633+ is_strict : false ,
634+ initial_conditions,
635+ final_conditions,
636+ } ;
637+
638+ ( puzzle, initial_board)
639+ }
640+
579641#[ allow( clippy:: identity_op) ]
580642fn create_robot_face_puzzle_and_solution ( ) -> ( Puzzle , Board ) {
581643 let size = 60 ;
@@ -625,7 +687,7 @@ fn create_robot_face_puzzle_and_solution() -> (Puzzle, Board) {
625687 let puzzle = Puzzle {
626688 title : "Robot face" . to_string ( ) ,
627689 summary : "Create a robot-like face from very few cells" . to_string ( ) ,
628- difficulty : Difficulty :: Medium ,
690+ difficulty : Difficulty :: Easy ,
629691 size,
630692 minimal_steps : 170 ,
631693 maximal_steps : 200 ,
@@ -637,6 +699,63 @@ fn create_robot_face_puzzle_and_solution() -> (Puzzle, Board) {
637699 ( puzzle, initial_board)
638700}
639701
702+ fn create_glider_collision_puzzle_and_solution ( ) -> ( Puzzle , Board ) {
703+ // Create two gliders on a collision course that will cancel each other out
704+ // First glider (moving down-right) starting at top-left
705+ // Second glider (moving up-left) starting at bottom-right
706+ let initial_board = Board :: with_live_cells (
707+ 12 ,
708+ vec ! [
709+ // First glider (top-left, moving down-right)
710+ Position { x: 2 , y: 1 } ,
711+ Position { x: 3 , y: 2 } ,
712+ Position { x: 1 , y: 3 } ,
713+ Position { x: 2 , y: 3 } ,
714+ Position { x: 3 , y: 3 } ,
715+ // Second glider (bottom-right, moving up-left)
716+ // Glider pattern rotated 180 degrees
717+ Position { x: 8 , y: 9 } ,
718+ Position { x: 7 , y: 8 } ,
719+ Position { x: 9 , y: 7 } ,
720+ Position { x: 8 , y: 7 } ,
721+ Position { x: 7 , y: 7 } ,
722+ ] ,
723+ ) ;
724+
725+ // After collision, the board should be empty or nearly empty
726+ let final_board = initial_board. advance ( 16 ) ;
727+ let final_conditions = final_board. to_exactly_matching_conditions ( ) ;
728+
729+ let puzzle = Puzzle {
730+ title : "Glider Collision" . to_string ( ) ,
731+ summary : "Make two gliders collide and cancel each other out" . to_string ( ) ,
732+ difficulty : Difficulty :: Medium ,
733+ size : 12 ,
734+ minimal_steps : 16 ,
735+ maximal_steps : 16 ,
736+ is_strict : true ,
737+ initial_conditions : vec ! [
738+ // First glider should be in top-left area
739+ Condition :: TestRectangle {
740+ x_range: 0 ..5 ,
741+ y_range: 0 ..5 ,
742+ min_live_count: 5 ,
743+ max_live_count: 5 ,
744+ } ,
745+ // Second glider should be in bottom-right area
746+ Condition :: TestRectangle {
747+ x_range: 7 ..12 ,
748+ y_range: 7 ..12 ,
749+ min_live_count: 5 ,
750+ max_live_count: 5 ,
751+ } ,
752+ ] ,
753+ final_conditions,
754+ } ;
755+
756+ ( puzzle, initial_board)
757+ }
758+
640759fn create_glider_migration_puzzle_and_solution ( ) -> ( Puzzle , Board ) {
641760 // Place a glider pattern in the top-left square.
642761 let initial_board = Board :: with_live_cells (
0 commit comments