diff --git a/demos/life/Makefile.in b/demos/life/Makefile.in index 14db842f1f..77da68dce4 100644 --- a/demos/life/Makefile.in +++ b/demos/life/Makefile.in @@ -13,11 +13,11 @@ top_srcdir = @top_srcdir@/.. top_builddir = ../.. program_dir = demos/life -DATAFILES = samples.inc +DATAFILES = samples.inc breeder.lif PROGRAM=life -OBJECTS=$(PROGRAM).o dialogs.o game.o +OBJECTS=$(PROGRAM).o dialogs.o game.o reader.o include ../../src/makeprog.env diff --git a/demos/life/bitmaps/info.bmp b/demos/life/bitmaps/info.bmp new file mode 100644 index 0000000000..3e27204ada Binary files /dev/null and b/demos/life/bitmaps/info.bmp differ diff --git a/demos/life/bitmaps/info.xpm b/demos/life/bitmaps/info.xpm new file mode 100644 index 0000000000..ac05447e24 --- /dev/null +++ b/demos/life/bitmaps/info.xpm @@ -0,0 +1,24 @@ +/* XPM */ +static char *info_xpm[] = { +/* columns rows colors chars-per-pixel */ +"16 16 2 1", +" c None", +". c Blue", +/* pixels */ +" ", +" .... ", +" ...... ", +" ...... ", +" .... ", +" ", +" ", +" ....... ", +" ..... ", +" ..... ", +" ..... ", +" ..... ", +" ..... ", +" ..... ", +" ..... ", +" ......... " +}; diff --git a/demos/life/bitmaps/open.bmp b/demos/life/bitmaps/open.bmp new file mode 100644 index 0000000000..bbf93fe033 Binary files /dev/null and b/demos/life/bitmaps/open.bmp differ diff --git a/demos/life/bitmaps/open.xpm b/demos/life/bitmaps/open.xpm new file mode 100644 index 0000000000..54748e910d --- /dev/null +++ b/demos/life/bitmaps/open.xpm @@ -0,0 +1,26 @@ +/* XPM */ +static char *open_xpm[] = { +/* columns rows colors chars-per-pixel */ +"16 15 5 1", +" c None", +". c Black", +"X c Yellow", +"o c Gray100", +"O c #bfbf00", +/* pixels */ +" ", +" ... ", +" . . .", +" ..", +" ... ...", +" .XoX....... ", +" .oXoXoXoXo. ", +" .XoXoXoXoX. ", +" .oXoX..........", +" .XoX.OOOOOOOOO.", +" .oo.OOOOOOOOO. ", +" .X.OOOOOOOOO. ", +" ..OOOOOOOOO. ", +" ........... ", +" " +}; diff --git a/demos/life/bitmaps/reset.bmp b/demos/life/bitmaps/reset.bmp index 41ea143e80..d66feb2384 100644 Binary files a/demos/life/bitmaps/reset.bmp and b/demos/life/bitmaps/reset.bmp differ diff --git a/demos/life/bitmaps/reset.xpm b/demos/life/bitmaps/reset.xpm index b9ebd02762..754d2d20a2 100644 --- a/demos/life/bitmaps/reset.xpm +++ b/demos/life/bitmaps/reset.xpm @@ -1,24 +1,24 @@ -/* XPM */ -static char *reset_xpm[] = { -/* columns rows colors chars-per-pixel */ -"16 16 2 1", -" c None", -". c Black", -/* pixels */ -" ", -" ", -" ", -" .. .. ", -" ... ... ", -" ... ... ", -" ...... ", -" .... ", -" .... ", -" ...... ", -" ... ... ", -" ... ... ", -" .. .. ", -" ", -" ", -" " -}; +/* XPM */ +static char *new_xpm[] = { +/* columns rows colors chars-per-pixel */ +"16 15 3 1", +" c None", +". c Black", +"X c Gray100", +/* pixels */ +" ", +" ........ ", +" .XXXXXX.. ", +" .XXXXXX.X. ", +" .XXXXXX.... ", +" .XXXXXXXXX. ", +" .XXXXXXXXX. ", +" .XXXXXXXXX. ", +" .XXXXXXXXX. ", +" .XXXXXXXXX. ", +" .XXXXXXXXX. ", +" .XXXXXXXXX. ", +" .XXXXXXXXX. ", +" ........... ", +" " +}; diff --git a/demos/life/breeder.lif b/demos/life/breeder.lif new file mode 100644 index 0000000000..5a6ca8d581 --- /dev/null +++ b/demos/life/breeder.lif @@ -0,0 +1,2523 @@ +#Life 1.05 +#D Breeder, the classic original +#D by Bill Gosper, early 1970's. +#D +#D This is the first pattern to +#D demonstrate that quadratic +#D growth was possible in the +#D Game of Life. Much better +#D results have been achieved +#D since then (see MAX). +#N +#P -368 -2 +*** +..* +.* +#P -374 -16 +...** +...** +. +. +. +...* +..*** +.*...* +*.***.* +.***** +. +. +. +. +. +. +. +. +. +. +. +. +. +....*** +...*...* +..*.....* +..**.*.** +. +. +.....* +....*.* +....*.* +.....* +. +.....** +.....** +#P -339 -16 +** +** +. +. +. +. +. +. +. +. +. +** +*.* +.** +. +. +. +. +. +. +. +. +...** +..*.* +..** +. +. +. +. +. +. +. +. +. +..** +..** +#P -334 -15 +*.* +** +.* +#P -333 15 +** +*.* +* +#P -307 -16 +** +** +. +. +. +. +. +. +. +. +. +** +*.* +.** +. +. +. +. +. +. +. +. +...** +..*.* +..** +. +. +. +. +. +. +. +. +. +..** +..** +#P -286 -31 +*.* +** +.* +#P -285 31 +** +*.* +* +#P -275 -16 +** +** +. +. +. +. +. +. +. +. +. +** +*.* +.** +. +. +. +. +. +. +. +. +...** +..*.* +..** +. +. +. +. +. +. +. +. +. +..** +..** +#P -238 -47 +*.* +** +.* +#P -237 47 +** +*.* +* +#P -243 -16 +** +** +. +. +. +. +. +. +. +. +. +** +*.* +.** +. +. +. +. +. +. +. +. +...** +..*.* +..** +. +. +. +. +. +. +. +. +. +..** +..** +#P -190 -63 +*.* +** +.* +#P -189 63 +** +*.* +* +#P -211 -16 +** +** +. +. +. +. +. +. +. +. +. +** +*.* +.** +. +. +. +. +. +. +. +. +...** +..*.* +..** +. +. +. +. +. +. +. +. +. +..** +..** +#P -179 -16 +** +** +. +. +. +. +. +.....* +.....*.* +.....** +.** +*..* +*..* +.** +. +. +. +. +. +. +. +. +...** +..*..* +..*..* +...** +.......** +.......*.* +.......* +. +. +. +. +. +..** +..** +#P -142 -79 +*.* +** +.* +#P -141 79 +** +*.* +* +#P -147 -16 +** +** +. +. +. +. +. +. +. +. +.** +*..* +*..* +.** +. +. +. +. +. +. +. +. +...** +..*..* +..*..* +...** +. +. +. +. +. +. +. +. +..** +..** +#P -126 -25 +* +*.* +** +#P -124 26 +** +*.* +* +#P -94 -95 +*.* +** +.* +#P -93 95 +** +*.* +* +#P -115 -16 +** +** +. +. +. +. +. +. +. +. +.** +*..* +*..* +.** +. +. +. +. +. +. +. +. +...** +..*..* +..*..* +...** +. +. +. +. +. +. +. +. +..** +..** +#P -78 -41 +* +*.* +** +#P -76 42 +** +*.* +* +#P -46 -111 +*.* +** +.* +#P -45 111 +** +*.* +* +#P -83 -16 +** +** +. +. +. +. +. +. +. +. +.** +*..* +*..* +.** +. +. +. +. +. +. +. +. +...** +..*..* +..*..* +...** +. +. +. +. +. +. +. +. +..** +..** +#P -30 -57 +* +*.* +** +#P -28 58 +** +*.* +* +#P 3 127 +** +*.* +* +#P 2 -127 +*.* +** +.* +#P -51 -16 +** +** +. +. +. +. +. +. +. +. +.** +*..* +*..* +.** +. +. +. +. +. +. +. +. +...** +..*..* +..*..* +...** +. +. +. +. +. +. +. +. +..** +..** +#P 18 -73 +* +*.* +** +#P -4 66 +** +*.* +* +#P -19 -16 +** +** +. +. +. +. +. +. +. +. +.** +*..* +*..* +.** +. +. +. +. +. +. +. +. +...** +..*..* +..*..* +...** +. +. +. +. +. +. +. +. +..** +..** +#P 66 -89 +* +*.* +** +#P 44 82 +** +*.* +* +#P 13 -16 +** +** +. +. +. +. +. +. +. +. +.** +*..* +*..* +.** +#P 15 18 +** +** +#P 26 -8 +.* +* +*** +#P 25 16 +.** +** +..* +#P -14 54 +** +** +#P -33 -110 +** +** +#P -22 -119 +*.* +** +.* +#P -1 -110 +** +** +#P 20 74 +** +*.* +* +#P 68 90 +** +*.* +* +#P -31 112 +** +** +#P -21 119 +** +*.* +* +#P 1 112 +** +** +#P 45 -16 +** +** +. +. +. +. +. +. +. +. +.** +*..* +*..* +.** +#P 47 18 +** +** +#P 48 23 +* +* +..** +#P 74 -24 +.* +* +*** +#P 73 32 +.** +** +..* +#P 77 -16 +** +** +. +. +. +. +. +. +. +. +.** +*..* +*..* +.** +#P 79 18 +** +** +. +. +. +** +** +#P 109 -16 +** +** +. +. +. +. +. +. +. +. +.** +*..* +*..* +.** +#P 111 18 +** +** +. +. +. +** +** +#P 122 -40 +.* +* +*** +#P 141 -16 +** +** +. +. +. +. +. +. +. +. +.** +*..* +*..* +.** +#P 143 18 +** +** +. +. +. +** +** +#P 173 -16 +** +** +. +. +. +. +. +. +. +. +.** +*..* +*..* +.** +#P 175 18 +** +** +. +. +. +** +** +#P 205 -16 +** +** +#P 207 18 +** +** +. +. +. +** +** +#P 215 -14 +* +*.* +** +#P 215 8 +.** +** +..* +#P 237 -16 +** +** +#P 239 18 +** +** +. +. +. +** +** +#P 263 -30 +* +*.* +** +#P 263 24 +.** +** +..* +#P 269 -21 +** +** +. +. +. +** +** +#P 271 18 +** +** +. +. +. +** +** +#P 287 -38 +* +*.* +** +#P 311 -46 +* +*.* +** +#P 311 40 +.** +** +..* +#P 335 48 +.** +** +..* +#P 170 -56 +.* +* +*** +#P 194 -64 +.* +* +*** +#P 188 -59 +** +** +#P 220 -59 +** +** +#P 252 -64 +** +** +. +. +. +** +** +#P 139 -80 +** +** +#P 107 -80 +** +** +#P 75 -80 +** +** +#P 31 -115 +** +** +. +. +. +** +** +#P -19 -151 +** +** +. +. +. +** +** +#P 50 49 +** +** +. +. +. +** +** +#P 74 49 +** +** +. +. +. +** +** +#P 90 49 +** +** +. +. +. +** +** +#P -34 147 +** +** +. +. +. +** +** +#P 22 147 +** +** +. +. +. +** +** +#P 38 147 +** +** +. +. +. +** +** +#P 105 112 +** +** +. +. +. +** +** +#P 89 112 +** +** +. +. +. +** +** +#P 33 112 +** +** +. +. +. +** +** +#P 21 -151 +** +** +. +. +. +** +** +#P 37 -151 +** +** +. +. +. +** +** +#P 26 -135 +*.* +** +.* +#P 87 -115 +** +** +. +. +. +** +** +#P 103 -115 +** +** +. +. +. +** +** +#P 171 -85 +** +** +. +. +. +** +** +#P 195 -85 +** +** +. +. +. +** +** +#P 211 -85 +** +** +. +. +. +** +** +#P 308 -64 +** +** +. +. +. +** +** +#P 324 -64 +** +** +. +. +. +** +** +#P 301 -21 +** +** +. +. +. +** +** +#P 325 -21 +** +** +. +. +. +** +** +#P 341 -21 +** +** +. +. +. +** +** +#P 343 18 +** +** +. +. +. +** +** +#P 327 18 +** +** +. +. +. +** +** +#P 303 18 +** +** +. +. +. +** +** +#P 333 62 +** +** +. +. +. +** +** +#P 349 62 +** +** +. +. +. +** +** +#P 277 62 +** +** +. +. +. +** +** +#P 362 -30 +.....** +.****.** +.****** +..**** +.* +*.* +*.* +....** +....*.* +......* +....*** +. +. +. +....*** +......* +....*.* +....** +*.* +*.* +.* +..**** +.****** +.****.** +.....** +#P 346 -28 +...** +..*.* +.*..* +......* +* +.....*.*.* +..*..*.*..* +...**.....*..* +........*.*.*..* +.....**.*...*..* +. +.....**.*...*..* +........*.*.*..* +...**.....*..* +..*..*.*..* +.....*.*.* +* +......* +.*..* +..*.* +...** +#P 352 -33 +.**** +****** +****.** +....** +#P 352 -6 +....** +****.** +****** +.**** +#P 331 -23 +.** +*..* +*.* +.* +. +. +. +.* +*.* +*..* +.** +#P 327 -30 +.*** +***** +***.** +...** +#P 327 -9 +...** +***.** +***** +.*** + +#P 313 -22 +.** +*..*....* +.**.....* +. +. +. +.**.....* +*..*....* +.** + +#P 294 -20 +** +** +. +** +** +#P 287 -27 +....** +...*..* +**.* +.....** +*...** +..*.* +. +. +. +. +. +. +. +..*.* +*...** +.....** +**.* +...*..* +....** +#P 364 9 +.......** +...****.** +...****** +....**** +..* +** +.*..* +..***.** +........* +........* +....*..** +.....** +. +.....** +....*..** +........* +........* +..***.** +.*..* +** +..* +....**** +...****** +...****.** +.......** +#P 350 10 +.*** +.* +....* +...* +. +......* +.....**** +........* +****..*.** +*.*.*.*....** +.**..*.* +. +.**..*.* +*.*.*.*....** +****..*.** +........* +.....**** +......* +. +...* +....* +.* +.*** +#P 356 6 +.**** +****** +****.** +....** +#P 342 -38 +.** +**** +**.** +..** +#P 356 33 +....** +****.** +****** +.**** +#P 346 38 +..** +**.** +**** +.** +#P 326 -2 +.* +* +. +.*.* +...* +.* +..* +#P 331 9 +.*** +***** +***.** +...** +#P 331 30 +...** +***.** +***** +.*** +#P 333 16 +.** +*..* +*.* +.* +. +. +. +.* +*.* +*..* +.** +#P 315 17 +.** +*..* +.** +. +. +. +.** +*..* +.** +#P 296 19 +** +** +. +** +** +#P 290 11 +..** +...** +.*.* +*** +*..* +*.*** +.*..* +..** +. +. +. +. +. +..** +.*..* +*.*** +*..* +*** +.*.* +...** +..** +#P 287 32 +.** +** +..* +#P 367 51 +...** +.*....* +.......* +.*.....* +..****** +. +. +. +. +...*** +.*...** +.*.*..** +*.....* +.***** +. +.***** +*.....* +.*.*..** +.*...** +...*** +. +. +. +. +..****** +.*.....* +.......* +.*....* +...** +#P 355 57 +..*..* +.***.** +**...*.** +.*...* +.*.*.*.** +..*****.*.* +...*....** +.........* +. +.........* +...*....** +..*****.*.* +.*.*.*.** +.*...* +**...*.** +.***.** +..*..* +#P 357 51 +.****** +*.....* +......* +*....* +.*.* +#P 357 75 +.*.* +*....* +......* +*.....* +.****** +#P 339 60 +.** +*..* +*.* +.* +. +. +. +.* +*.* +*..* +.** +#P 332 54 +.***** +*....* +.....* +*...* +..* +#P 332 72 +..* +*...* +.....* +*....* +.***** +#P 322 60 +..**.* +.****.** +*....** +*.* +.* +. +.* +*.* +*....** +.****.** +..**.* +#P 306 62 +**.** +.*** +.** +. +.** +.*** +**.** +#P 302 63 +* +** +. +** +* +#P 292 57 +.......* +......*.* +.........* +....*.** +..*.** +***..** +.**..** +. +. +. +.**..** +***..** +..*.** +....*.** +.........* +......*.* +.......* +#P 272 56 +.***** +*....* +.....* +*...* +..* +#P 272 70 +..* +*...* +.....* +*....* +.***** +#P 347 81 +*..* +....* +*...* +.**** +#P 343 -74 +.**** +****** +****.** +....** +. +. +. +. +..** +.*..** +***..* +*....* +***** +. +***** +*....* +***..* +.*..** +..** +. +. +. +. +....** +****.** +****** +.**** +#P 330 -70 +...* +....* +..**** +**...*.** +.*.*.*.* +.*...***..* +..*.*...* +...*....*** +. +. +. +...*....*** +..*.*...* +.*...***..* +.*.*.*.* +**...*.** +..**** +....* +...* +#P 332 -75 +....** +****.** +****** +.**** +#P 332 -50 +.**** +****** +****.** +....** +#P 314 -66 +.** +*..* +*.* +.* +. +. +. +.* +*.* +*..* +.** +#P 307 -72 +...** +***.** +***** +.*** +#P 307 -53 +.*** +***** +***.** +...** +#P 297 -69 +..* +..* +. +......* +.****.* +*..*.** +*.* +.* +. +.* +*.* +*..*.** +.****.* +......* +. +..* +..* +#P 281 -65 +.*.* +....* +**.* +..* +. +..* +**.* +....* +.*.* +#P 277 -63 +* +*** +. +*** +* +#P 268 -68 +.....*** +...*..** +..*...*.* +*...* +*...** +* +.*...* +. +.*...* +* +*...** +*...* +..*...*.* +...*..** +.....*** +#P 322 -80 +..** +**.** +**** +.** +#P 247 -70 +...** +***.** +***** +.*** +#P 236 -94 +.....** +.****.** +.****** +..**** +. +. +..** +.*...* +.*....* +*.....* +.**.*** +. +. +. +.**.*** +*.....* +.*....* +.*...* +..** +. +. +..**** +.****** +.****.** +.....** +#P 232 -91 +.* +*..* +. +. +. +.* +..* +. +. +. +. +. +..* +.* +. +. +. +*..* +.* +#P 226 -97 +.**** +****** +****.** +....** +#P 226 -70 +....** +****.** +****** +.**** +#P 218 -89 +.....*** +...***** +..*** +.*...* +**..*....** +*......*** +.******** +. +.******** +*......*** +**..*....** +.*...* +..*** +...***** +.....*** +#P 216 -102 +.** +**** +**.** +..** +#P 218 -94 +*** +* +.* +#P 218 -72 +.* +* +*** +#P 201 -73 +...** +***.** +***** +.*** +#P 201 -94 +.*** +***** +***.** +...** +#P 201 -88 +.** +.** +*..* +*.* +.* +. +. +. +.* +*.* +*..* +.** +.** +#P 183 -86 +.** +*..* +.** +. +. +. +.** +*..* +.**. +#P 156 -93 +....*.* +...**..* +..***..* +.*** +.*.*..** +**.***.* +.*......* +..*....* +....***** +........** +........** +. +........** +........** +....***** +..*....* +.*......* +**.***.* +.*.*..** +.*** +..***..* +...**..* +....*.* +#P 141 -92 +.*** +***** +***.** +...** +#P 122 -125 +.**** +****** +****.** +....** +. +. +. +. +..** +.*..** +***..* +*....* +***** +. +***** +*....* +***..* +.*..** +..** +. +. +. +. +....** +****.** +****** +.**** +#P 109 -121 +...* +....* +..**** +**...*.** +.*.*.*.* +.*...***..* +..*.*...* +...*....*** +. +. +. +...*....*** +..*.*...* +.*...***..* +.*.*.*.* +**...*.** +..**** +....* +...* +#P 111 -126 +....** +****.** +****** +.**** +#P 111 -101 +.**** +****** +****.** +....** +#P 93 -117 +.** +*..* +*.* +.* +. +. +. +.* +*.* +*..* +.** +#P 86 -123 +...** +***.** +***** +.*** +#P 86 -104 +.*** +***** +***.** +...** +#P 76 -120 +..* +..* +. +......* +.****.* +*..*.** +*.* +.* +. +.* +*.* +*..*.** +.****.* +......* +. +..* +..* +#P 60 -116 +.*.* +....* +**.* +..* +. +..* +**.* +....* +.*.* +#P 56 -114 +* +*** +. +*** +* +#P 47 -119 +.....*** +...*..** +..*...*.* +*...* +*...** +* +.*...* +. +.*...* +* +*...** +*...* +..*...*.* +...*..** +.....*** +#P 101 -131 +..** +**.** +**** +.** +#P 90 -97 +* +*.* +** +#P 26 -121 +...** +***.** +***** +.*** +#P 51 -160 +.****** +*.....* +......* +*....* +..** +. +..** +.*.** +**.*.* +*.**.** +*...** +..*** +. +..*** +*...** +*.**.** +**.*.* +.*.** +..** +. +..** +*....* +......* +*.....* +.****** +#P 43 -154 +..*** +*...* +* +* +.*..* +..*.* +. +..*.* +.*..* +* +* +*...* +..*** +#P 40 -164 +..** +*....* +......* +*.....* +.****** +#P 40 -136 +.****** +*.....* +......* +*....* +..** +#P 27 -153 +..* +.*.* +* +.* +. +. +. +.* +* +.*.* +..* +#P 26 -163 +..* +*.* +*.* +#P 15 -161 +..* +*...* +.....* +*....* +.***** +#P 15 -139 +.***** +*....* +.....* +*...* +..* +#P 15 -153 +* +.* +.* +* +. +. +. +* +.* +.* +* +#P 8 -155 +...** +...** +...** +**.** +.*.* +.*** +. +. +. +.*** +.*.* +**.** +...** +...** +...** +#P 5 -151 +** +** +. +. +. +** +** +#P -7 -152 +.** +*..* +.** +. +. +. +.** +*..* +.** +#P -33 -161 +.*.* +.*.* +.*.** +...** +*..* +.** +#P -33 -140 +.** +*..* +...** +.*.** +.*.* +.*.* +#P -45 -159 +..* +*...* +.....* +*....* +.***** +#P -45 -141 +.***** +*....* +.....* +*...* +..* +#P 30 -168 +*..* +....* +*...* +.**** +#P 111 38 +......** +....*....* +..........* +....*.....* +.....****** +.* +.*** +*.**..* +..***..* +.*****..* +.***.*.*** +......**.** +.....**.** +. +. +. +.....**.** +......**.** +.***.*.*** +.*****..* +..***..* +*.**..* +.*** +.* +.....****** +....*.....* +..........* +....*....* +......** +#P 104 38 +.****** +*.....* +......* +*....* +..** +#P 104 62 +..** +*....* +......* +*.....* +.****** +#P 97 45 +......* +.....*** +..*** +.*...*...* +*..*.*....* +*........* +.******** +. +.******** +*........* +*..*.*....* +.*...*...* +..*** +.....*** +......* +#P 97 40 +.** +** +..* +#P 97 62 +..* +** +.** +#P 79 41 +.***** +*....* +.....* +*...* +..* +. +..** +.*..* +.*.* +..* +. +. +. +..* +.*.* +.*..* +..** +. +..* +*...* +.....* +*....* +.***** +#P 62 48 +.** +*..* +.** +. +. +. +.** +*..* +.** +#P 43 50 +** +** +. +** +** +#P 36 41 +....** +...*** +.**...* +.*...* +* +***..** +*.*.*** +.***.** +...** +. +. +. +. +. +...** +.***.** +*.*.*** +***..** +* +.*...* +.**...* +...*** +....** +#P 19 43 +.***** +*....* +.....* +*...* +..* +#P 18 54 +** +** +#P 94 68 +*..* +....* +*...* +.**** +#P 124 102 +.**** +****** +****.** +....** +. +. +. +. +..** +.*..** +***..* +*....* +***** +. +***** +*....* +***..* +.*..** +..** +. +. +. +. +....** +****.** +****** +.**** +#P 111 106 +...* +....* +..**** +**...*.** +.*.*.*.* +.*...***..* +..*.*...* +...*....*** +. +. +. +...*....*** +..*.*...* +.*...***..* +.*.*.*.* +**...*.** +..**** +....* +...* +#P 113 101 +....** +****.** +****** +.**** +#P 113 126 +.**** +****** +****.** +....** +#P 95 110 +.** +*..* +*.* +.* +. +. +. +.* +*.* +*..* +.** +#P 88 104 +...** +***.** +***** +.*** +#P 88 123 +.*** +***** +***.** +...** +#P 78 107 +..* +..* +. +......* +.****.* +*..*.** +*.* +.* +. +.* +*.* +*..*.** +.****.* +......* +. +..* +..* +#P 62 111 +.*.* +....* +**.* +..* +. +..* +**.* +....* +.*.* +#P 58 113 +* +*** +. +*** +* +#P 49 108 +.....*** +...*..** +..*...*.* +*...* +*...** +* +.*...* +. +.*...* +* +*...** +*...* +..*...*.* +...*..** +.....*** +#P 28 121 +.*** +***** +***.** +...** +#P 103 131 +.** +**** +**.** +..** +#P 92 98 +** +*.* +* +#P 51 137 +...**** +..****** +..****.** +......** +. +. +. +...*** +.** +.*....** +**.**..* +.......* +....*** +. +....*** +.......* +**.**..* +.*....** +.** +...*** +. +. +. +......** +..****.** +..****** +...**** +#P 43 143 +....* +....** +..*..* +*** +.** +..*.* +....* +. +....* +..*.* +.** +*** +..*..* +....** +....* +#P 42 136 +....** +****.** +****** +.**** +#P 42 161 +.**** +****** +****.** +....** +#P 28 145 +..* +.** +*** +. +. +. +. +. +*** +.** +..* +#P 17 139 +...** +***.** +***** +.*** +#P 17 158 +.*** +***** +***.** +...** +#P 16 146 +** +** +#P 16 153 +** +** +#P 9 143 +...** +..*..* +.....* +** +. +.*.* +..* +. +..* +.*.* +. +** +.....* +..*..* +...** +#P -15 139 +...............* +.............**.* +............*...* +........****.*.* +.......*.*...** +.**....*.* +**.*..**.** +.**.***..**** +...*...**.*.** +.........**.** +...........* +. +...........* +.........**.** +...*...**.*.** +.**.***..**** +**.*..**.** +.**....*.* +.......*.*...** +........****.*.* +............*...* +.............**.* +...............* +#P -21 144 +..* +.*.* +*...* +.*..* +.**.** +. +. +. +.**.** +.*..* +*...* +.*.* +..* +#P -43 141 +...** +***.** +***** +.*** +#P -43 156 +.*** +***** +***.** +...** +#P 28 164 +.** +* +#P 32 166 +.** +**** +**.** +..** +#P 27 135 +** +*.* +* diff --git a/demos/life/dialogs.cpp b/demos/life/dialogs.cpp index 0d8989793e..3eab611574 100644 --- a/demos/life/dialogs.cpp +++ b/demos/life/dialogs.cpp @@ -93,16 +93,16 @@ LifeSamplesDialog::LifeSamplesDialog(wxWindow *parent) 0, NULL, wxLB_SINGLE | wxLB_NEEDED_SB | wxLB_HSCROLL ); - for (unsigned i = 0; i < (sizeof(g_shapes) / sizeof(LifeShape)); i++) - m_list->Append(g_shapes[i].m_name); + for (unsigned i = 0; i < (sizeof(g_patterns) / sizeof(LifePattern)); i++) + m_list->Append(g_patterns[i].m_name); // descriptions wxStaticBox *statbox = new wxStaticBox( this, -1, _("Description")); m_life = new Life(); - m_life->SetShape(g_shapes[0]); + m_life->SetPattern(g_patterns[0]); m_canvas = new LifeCanvas( this, m_life, FALSE ); m_text = new wxTextCtrl( this, -1, - g_shapes[0].m_desc, + g_patterns[0].m_description, wxDefaultPosition, wxSize(300, 60), wxTE_MULTILINE | wxTE_READONLY); @@ -136,9 +136,9 @@ LifeSamplesDialog::~LifeSamplesDialog() m_canvas->Destroy(); } -const LifeShape& LifeSamplesDialog::GetShape() +const LifePattern& LifeSamplesDialog::GetPattern() { - return g_shapes[m_value]; + return g_patterns[m_value]; } void LifeSamplesDialog::OnListBox(wxCommandEvent& event) @@ -148,15 +148,14 @@ void LifeSamplesDialog::OnListBox(wxCommandEvent& event) if (sel != -1) { m_value = m_list->GetSelection(); - m_text->SetValue(g_shapes[ sel ].m_desc); - m_life->SetShape(g_shapes[ sel ]); + m_text->SetValue(g_patterns[ sel ].m_description); + m_life->SetPattern(g_patterns[ sel ]); - // quick and dirty :-) - if ((g_shapes[ sel ].m_width > 36) || - (g_shapes[ sel ].m_height > 22)) - m_canvas->SetCellSize(2); - else + // these values shouldn't be hardcoded... + if ((size_t)sel < (sizeof(g_patterns) / sizeof(LifePattern)) - 3) m_canvas->SetCellSize(8); + else + m_canvas->SetCellSize(2); } } diff --git a/demos/life/dialogs.h b/demos/life/dialogs.h index b2187cb0c3..e41e45953c 100644 --- a/demos/life/dialogs.h +++ b/demos/life/dialogs.h @@ -44,7 +44,7 @@ public: ~LifeSamplesDialog(); // members - const LifeShape& GetShape(); + const LifePattern& GetPattern(); // event handlers void OnListBox(wxCommandEvent &event); diff --git a/demos/life/game.cpp b/demos/life/game.cpp index f5c2e09f3b..46264b5238 100644 --- a/demos/life/game.cpp +++ b/demos/life/game.cpp @@ -117,17 +117,24 @@ bool CellBox::SetCell(int dx, int dy, bool alive) Life::Life() { - m_numcells = 0; - m_boxes = new CellBox *[HASHSIZE]; - m_head = NULL; - m_available = NULL; + // pattern description + m_name = _(""); + m_rules = _(""); + m_description = _(""); + + // pattern data + m_numcells = 0; + m_boxes = new CellBox *[HASHSIZE]; + m_head = NULL; + m_available = NULL; for (int i = 0; i < HASHSIZE; i++) m_boxes[i] = NULL; - m_cells = new Cell[ARRAYSIZE]; - m_ncells = 0; - m_findmore = FALSE; - m_changed = FALSE; + // state vars for BeginFind & FindMore + m_cells = new Cell[ARRAYSIZE]; + m_ncells = 0; + m_findmore = FALSE; + m_changed = FALSE; } Life::~Life() @@ -145,8 +152,6 @@ void Life::Clear() { CellBox *c, *nc; - m_numcells = 0; - // clear the hash table pointers for (int i = 0; i < HASHSIZE; i++) m_boxes[i] = NULL; @@ -170,6 +175,12 @@ void Life::Clear() c = nc; } m_available = NULL; + + // reset state + m_name = _(""); + m_rules = _(""); + m_description = _(""); + m_numcells = 0; } // -------------------------------------------------------------------------- @@ -204,19 +215,38 @@ void Life::SetCell(wxInt32 x, wxInt32 y, bool alive) } } -void Life::SetShape(const LifeShape& shape) +void Life::SetPattern(const LifePattern& pattern) { - char *p = shape.m_data; - - int i0 = -(shape.m_width / 2); - int j0 = -(shape.m_height / 2); - int i1 = i0 + shape.m_width - 1; - int j1 = j0 + shape.m_height - 1; + wxArrayString data = pattern.m_shape; + wxString line; + long x = 0, + y = 0; Clear(); - for (int j = j0; j <= j1; j++) - for (int i = i0; i <= i1; i++) - SetCell(i, j, *(p++) == '*'); + for (size_t n = 0; n < data.GetCount(); n++) + { + line = data[n]; + + if ( (line.GetChar(0) != wxT('*')) && + (line.GetChar(0) != wxT('.')) ) + { + // assume that it is a digit or a minus sign + line.BeforeFirst(wxT(' ')).ToLong(&x); + line.AfterFirst(wxT(' ')).ToLong(&y); + } + else + { + // pattern data + for (size_t k = 0; k < line.Len(); k++) + SetCell(x + k, y, line.GetChar(k) == wxT('*')); + + y++; + } + } + + m_name = pattern.m_name; + m_rules = pattern.m_rules; + m_description = pattern.m_description; } // -------------------------------------------------------------------------- @@ -337,110 +367,110 @@ void Life::KillBox(CellBox *c) Cell Life::FindCenter() { - double i, j; + double sx, sy; int n; - i = 0.0; - j = 0.0; + sx = 0.0; + sy = 0.0; n = 0; CellBox *c; for (c = m_head; c; c = c->m_next) if (!c->m_dead) { - i += c->m_x; - j += c->m_y; + sx += c->m_x; + sy += c->m_y; n++; } if (n > 0) { - i = (i / n) + CELLBOX / 2; - j = (j / n) + CELLBOX / 2; + sx = (sx / n) + CELLBOX / 2; + sy = (sy / n) + CELLBOX / 2; } Cell cell; - cell.i = (wxInt32) i; - cell.j = (wxInt32) j; + cell.i = (wxInt32) sx; + cell.j = (wxInt32) sy; return cell; } Cell Life::FindNorth() { - wxInt32 i = 0, j = 0; + wxInt32 x = 0, y = 0; bool first = TRUE; CellBox *c; for (c = m_head; c; c = c->m_next) - if (!c->m_dead && ((first) || (c->m_y < j))) + if (!c->m_dead && ((first) || (c->m_y < y))) { - i = c->m_x; - j = c->m_y; + x = c->m_x; + y = c->m_y; first = FALSE; } Cell cell; - cell.i = first? 0 : i + CELLBOX / 2; - cell.j = first? 0 : j + CELLBOX / 2; + cell.i = first? 0 : x + CELLBOX / 2; + cell.j = first? 0 : y + CELLBOX / 2; return cell; } Cell Life::FindSouth() { - wxInt32 i = 0, j = 0; + wxInt32 x = 0, y = 0; bool first = TRUE; CellBox *c; for (c = m_head; c; c = c->m_next) - if (!c->m_dead && ((first) || (c->m_y > j))) + if (!c->m_dead && ((first) || (c->m_y > y))) { - i = c->m_x; - j = c->m_y; + x = c->m_x; + y = c->m_y; first = FALSE; } Cell cell; - cell.i = first? 0 : i + CELLBOX / 2; - cell.j = first? 0 : j + CELLBOX / 2; + cell.i = first? 0 : x + CELLBOX / 2; + cell.j = first? 0 : y + CELLBOX / 2; return cell; } Cell Life::FindWest() { - wxInt32 i = 0, j = 0; + wxInt32 x = 0, y = 0; bool first = TRUE; CellBox *c; for (c = m_head; c; c = c->m_next) - if (!c->m_dead && ((first) || (c->m_x < i))) + if (!c->m_dead && ((first) || (c->m_x < x))) { - i = c->m_x; - j = c->m_y; + x = c->m_x; + y = c->m_y; first = FALSE; } Cell cell; - cell.i = first? 0 : i + CELLBOX / 2; - cell.j = first? 0 : j + CELLBOX / 2; + cell.i = first? 0 : x + CELLBOX / 2; + cell.j = first? 0 : y + CELLBOX / 2; return cell; } Cell Life::FindEast() { - wxInt32 i = 0, j = 0; + wxInt32 x = 0, y = 0; bool first = TRUE; CellBox *c; for (c = m_head; c; c = c->m_next) - if (!c->m_dead && ((first) || (c->m_x > i))) + if (!c->m_dead && ((first) || (c->m_x > x))) { - i = c->m_x; - j = c->m_y; + x = c->m_x; + y = c->m_y; first = FALSE; } Cell cell; - cell.i = first? 0 : i + CELLBOX / 2; - cell.j = first? 0 : j + CELLBOX / 2; + cell.i = first? 0 : x + CELLBOX / 2; + cell.j = first? 0 : y + CELLBOX / 2; return cell; } @@ -453,35 +483,35 @@ Cell Life::FindEast() // argument (or pass 0, the default value) to post alive cells // only, else it will post cells which have changed. // -void Life::DoLine(wxInt32 i, wxInt32 j, wxUint32 live, wxUint32 old) +void Life::DoLine(wxInt32 x, wxInt32 y, wxUint32 live, wxUint32 old) { wxUint32 diff = (live ^ old) & 0xff; if (!diff) return; - for (wxInt32 k = 8; k; k--, i++) + for (wxInt32 k = 8; k; k--, x++) { if (diff & 0x01) { - m_cells[m_ncells].i = i; - m_cells[m_ncells].j = j; + m_cells[m_ncells].i = x; + m_cells[m_ncells].j = y; m_ncells++; } diff >>= 1; } } -void Life::BeginFind(wxInt32 i0, wxInt32 j0, wxInt32 i1, wxInt32 j1, bool changed) +void Life::BeginFind(wxInt32 x0, wxInt32 y0, wxInt32 x1, wxInt32 y1, bool changed) { // TODO: optimize for the case where the maximum number of // cellboxes that fit in the specified viewport is smaller // than the current total of boxes; iterating over the list // should then be faster than searching in the hash table. - m_i0 = m_i = i0 & 0xfffffff8; - m_j0 = m_j = j0 & 0xfffffff8; - m_i1 = (i1 + 7) & 0xfffffff8; - m_j1 = (j1 + 7) & 0xfffffff8; + m_x0 = m_x = x0 & 0xfffffff8; + m_y0 = m_y = y0 & 0xfffffff8; + m_x1 = (x1 + 7) & 0xfffffff8; + m_y1 = (y1 + 7) & 0xfffffff8; m_findmore = TRUE; m_changed = changed; @@ -495,10 +525,10 @@ bool Life::FindMore(Cell *cells[], size_t *ncells) if (m_changed) { - for ( ; m_j <= m_j1; m_j += 8, m_i = m_i0) - for ( ; m_i <= m_i1; m_i += 8) + for ( ; m_y <= m_y1; m_y += 8, m_x = m_x0) + for ( ; m_x <= m_x1; m_x += 8) { - if ((c = LinkBox(m_i, m_j, FALSE)) == NULL) + if ((c = LinkBox(m_x, m_y, FALSE)) == NULL) continue; // check whether there is enough space left in the array @@ -508,22 +538,22 @@ bool Life::FindMore(Cell *cells[], size_t *ncells) return FALSE; } - DoLine(m_i, m_j , c->m_live1, c->m_old1 ); - DoLine(m_i, m_j + 1, c->m_live1 >> 8, c->m_old1 >> 8 ); - DoLine(m_i, m_j + 2, c->m_live1 >> 16, c->m_old1 >> 16); - DoLine(m_i, m_j + 3, c->m_live1 >> 24, c->m_old1 >> 24); - DoLine(m_i, m_j + 4, c->m_live2, c->m_old2 ); - DoLine(m_i, m_j + 5, c->m_live2 >> 8, c->m_old2 >> 8 ); - DoLine(m_i, m_j + 6, c->m_live2 >> 16, c->m_old2 >> 16); - DoLine(m_i, m_j + 7, c->m_live2 >> 24, c->m_old2 >> 24); + DoLine(m_x, m_y , c->m_live1, c->m_old1 ); + DoLine(m_x, m_y + 1, c->m_live1 >> 8, c->m_old1 >> 8 ); + DoLine(m_x, m_y + 2, c->m_live1 >> 16, c->m_old1 >> 16); + DoLine(m_x, m_y + 3, c->m_live1 >> 24, c->m_old1 >> 24); + DoLine(m_x, m_y + 4, c->m_live2, c->m_old2 ); + DoLine(m_x, m_y + 5, c->m_live2 >> 8, c->m_old2 >> 8 ); + DoLine(m_x, m_y + 6, c->m_live2 >> 16, c->m_old2 >> 16); + DoLine(m_x, m_y + 7, c->m_live2 >> 24, c->m_old2 >> 24); } } else { - for ( ; m_j <= m_j1; m_j += 8, m_i = m_i0) - for ( ; m_i <= m_i1; m_i += 8) + for ( ; m_y <= m_y1; m_y += 8, m_x = m_x0) + for ( ; m_x <= m_x1; m_x += 8) { - if ((c = LinkBox(m_i, m_j, FALSE)) == NULL) + if ((c = LinkBox(m_x, m_y, FALSE)) == NULL) continue; // check whether there is enough space left in the array @@ -533,14 +563,14 @@ bool Life::FindMore(Cell *cells[], size_t *ncells) return FALSE; } - DoLine(m_i, m_j , c->m_live1 ); - DoLine(m_i, m_j + 1, c->m_live1 >> 8 ); - DoLine(m_i, m_j + 2, c->m_live1 >> 16); - DoLine(m_i, m_j + 3, c->m_live1 >> 24); - DoLine(m_i, m_j + 4, c->m_live2 ); - DoLine(m_i, m_j + 5, c->m_live2 >> 8 ); - DoLine(m_i, m_j + 6, c->m_live2 >> 16); - DoLine(m_i, m_j + 7, c->m_live2 >> 24); + DoLine(m_x, m_y , c->m_live1 ); + DoLine(m_x, m_y + 1, c->m_live1 >> 8 ); + DoLine(m_x, m_y + 2, c->m_live1 >> 16); + DoLine(m_x, m_y + 3, c->m_live1 >> 24); + DoLine(m_x, m_y + 4, c->m_live2 ); + DoLine(m_x, m_y + 5, c->m_live2 >> 8 ); + DoLine(m_x, m_y + 6, c->m_live2 >> 16); + DoLine(m_x, m_y + 7, c->m_live2 >> 24); } } diff --git a/demos/life/game.h b/demos/life/game.h index f88644cb9b..cca12fae4b 100644 --- a/demos/life/game.h +++ b/demos/life/game.h @@ -29,45 +29,44 @@ #endif // -------------------------------------------------------------------------- -// Cell -// -------------------------------------------------------------------------- - -// A Cell is just a struct which contains a pair of (i, j) coords. -// These structs are not used internally anywhere; they are just -// used to pass cell coordinates around. - -struct Cell -{ - wxInt32 i; - wxInt32 j; -}; - -// -------------------------------------------------------------------------- -// LifeShape +// LifePattern // -------------------------------------------------------------------------- // A class which holds a pattern -class LifeShape +class LifePattern { public: - LifeShape(wxString name, - wxString desc, - int width, - int height, - char *data) + // This ctor is used by the LifeReader class + LifePattern(wxString name, + wxString description, + wxString rules, + wxArrayString shape) { - m_name = name; - m_desc = desc; - m_width = width; - m_height = height; - m_data = data; - } + m_name = name; + m_description = description; + m_rules = rules; + m_shape = shape; + }; + + // A more convenient ctor for the built-in samples + LifePattern(wxString name, + wxString description, + int width, + int height, + const char *shape) + { + m_name = name; + m_description = description; + m_rules = _(""); + m_shape.Add( wxString::Format("%i %i", -width/2, -height/2) ); + for(int j = 0; j < height; j++) + m_shape.Add( wxString(shape + (j * width), (size_t) width) ); + }; - wxString m_name; - wxString m_desc; - int m_width; - int m_height; - char *m_data; + wxString m_name; + wxString m_description; + wxString m_rules; + wxArrayString m_shape; }; @@ -75,8 +74,17 @@ public: // Life // -------------------------------------------------------------------------- +// A struct used to pass cell coordinates around +struct Cell +{ + wxInt32 i; + wxInt32 j; +}; + +// A private class that contains data about a block of cells class CellBox; +// A class that models a Life game instance class Life { public: @@ -85,10 +93,12 @@ public: ~Life(); // accessors - inline wxUint32 GetNumCells() const { return m_numcells; }; - bool IsAlive (wxInt32 x, wxInt32 y); - void SetCell (wxInt32 x, wxInt32 y, bool alive = TRUE); - void SetShape (const LifeShape &shape); + inline wxUint32 GetNumCells() const { return m_numcells; }; + inline wxString GetRules() const { return m_rules; }; + inline wxString GetDescription() const { return m_description; }; + bool IsAlive(wxInt32 x, wxInt32 y); + void SetCell(wxInt32 x, wxInt32 y, bool alive = TRUE); + void SetPattern(const LifePattern &pattern); // game control void Clear(); @@ -119,8 +129,8 @@ public: // FALSE, then the operation is not complete: just process all cells // and call FillMore() again. // - void BeginFind(wxInt32 i0, wxInt32 j0, - wxInt32 i1, wxInt32 j1, + void BeginFind(wxInt32 x0, wxInt32 y0, + wxInt32 x1, wxInt32 y1, bool changed); bool FindMore(Cell *cells[], size_t *ncells); @@ -131,20 +141,28 @@ private: void KillBox(CellBox *c); // helper for BeginFind & FindMore - void DoLine(wxInt32 i, wxInt32 j, wxUint32 alive, wxUint32 old = 0); + void DoLine(wxInt32 x, wxInt32 y, wxUint32 alive, wxUint32 old = 0); - CellBox *m_head; // list of alive boxes - CellBox *m_available; // list of reusable dead boxes - CellBox **m_boxes; // hash table of alive boxes - wxUint32 m_numcells; // population (number of alive cells) - Cell *m_cells; // cell array for FindMore() - size_t m_ncells; // number of valid cells in cell array - wxInt32 m_i, m_j, // state vars for FindMore() - m_i0, m_j0, - m_i1, m_j1; - bool m_changed; - bool m_findmore; + // pattern description + wxString m_name; // name (currently unused) + wxString m_rules; // rules (currently unused) + wxString m_description; // description + + // pattern data + CellBox *m_head; // list of alive boxes + CellBox *m_available; // list of reusable dead boxes + CellBox **m_boxes; // hash table of alive boxes + wxUint32 m_numcells; // population (number of alive cells) + + // state vars for BeginFind & FindMore + Cell *m_cells; // array of cells + size_t m_ncells; // number of valid entries in m_cells + wxInt32 m_x, m_y, // counters and search mode + m_x0, m_y0, + m_x1, m_y1; + bool m_changed; + bool m_findmore; }; #endif // _LIFE_GAME_H_ diff --git a/demos/life/life.cpp b/demos/life/life.cpp index 8b29dca570..f01e3e0be7 100644 --- a/demos/life/life.cpp +++ b/demos/life/life.cpp @@ -29,10 +29,13 @@ #endif #include "wx/statline.h" +#include "wx/wfstream.h" +#include "wx/filedlg.h" #include "life.h" #include "game.h" #include "dialogs.h" +#include "reader.h" // -------------------------------------------------------------------------- // resources @@ -44,10 +47,12 @@ // bitmap buttons for the toolbar #include "bitmaps/reset.xpm" + #include "bitmaps/open.xpm" #include "bitmaps/play.xpm" #include "bitmaps/stop.xpm" #include "bitmaps/zoomin.xpm" #include "bitmaps/zoomout.xpm" + #include "bitmaps/info.xpm" // navigator #include "bitmaps/north.xpm" @@ -67,22 +72,14 @@ enum // timer ID_TIMER = 1001, - // menu items and toolbar buttons - ID_RESET, + // file menu + ID_NEW, + ID_OPEN, ID_SAMPLES, ID_ABOUT, ID_EXIT, - ID_START, - ID_STEP, - ID_STOP, - ID_ZOOMIN, - ID_ZOOMOUT, - ID_TOPSPEED, - // speed selection slider - ID_SLIDER, - - // navigation + // view menu ID_SHOWNAV, ID_ORIGIN, ID_CENTER, @@ -90,6 +87,18 @@ enum ID_SOUTH, ID_EAST, ID_WEST, + ID_ZOOMIN, + ID_ZOOMOUT, + ID_INFO, + + // game menu + ID_START, + ID_STEP, + ID_STOP, + ID_TOPSPEED, + + // speed selection slider + ID_SLIDER, }; // -------------------------------------------------------------------------- @@ -98,14 +107,11 @@ enum // Event tables BEGIN_EVENT_TABLE(LifeFrame, wxFrame) + EVT_MENU (ID_NEW, LifeFrame::OnMenu) + EVT_MENU (ID_OPEN, LifeFrame::OnOpen) EVT_MENU (ID_SAMPLES, LifeFrame::OnSamples) - EVT_MENU (ID_RESET, LifeFrame::OnMenu) EVT_MENU (ID_ABOUT, LifeFrame::OnMenu) EVT_MENU (ID_EXIT, LifeFrame::OnMenu) - EVT_MENU (ID_START, LifeFrame::OnMenu) - EVT_MENU (ID_STEP, LifeFrame::OnMenu) - EVT_MENU (ID_STOP, LifeFrame::OnMenu) - EVT_MENU (ID_TOPSPEED, LifeFrame::OnMenu) EVT_MENU (ID_SHOWNAV, LifeFrame::OnMenu) EVT_MENU (ID_ORIGIN, LifeFrame::OnNavigate) EVT_BUTTON (ID_CENTER, LifeFrame::OnNavigate) @@ -115,6 +121,11 @@ BEGIN_EVENT_TABLE(LifeFrame, wxFrame) EVT_BUTTON (ID_WEST, LifeFrame::OnNavigate) EVT_MENU (ID_ZOOMIN, LifeFrame::OnZoom) EVT_MENU (ID_ZOOMOUT, LifeFrame::OnZoom) + EVT_MENU (ID_INFO, LifeFrame::OnMenu) + EVT_MENU (ID_START, LifeFrame::OnMenu) + EVT_MENU (ID_STEP, LifeFrame::OnMenu) + EVT_MENU (ID_STOP, LifeFrame::OnMenu) + EVT_MENU (ID_TOPSPEED, LifeFrame::OnMenu) EVT_COMMAND_SCROLL (ID_SLIDER, LifeFrame::OnSlider) EVT_TIMER (ID_TIMER, LifeFrame::OnTimer) EVT_CLOSE ( LifeFrame::OnClose) @@ -128,7 +139,10 @@ BEGIN_EVENT_TABLE(LifeCanvas, wxWindow) EVT_PAINT ( LifeCanvas::OnPaint) EVT_SCROLLWIN ( LifeCanvas::OnScroll) EVT_SIZE ( LifeCanvas::OnSize) - EVT_MOUSE_EVENTS ( LifeCanvas::OnMouse) + EVT_MOTION ( LifeCanvas::OnMouse) + EVT_LEFT_DOWN ( LifeCanvas::OnMouse) + EVT_LEFT_UP ( LifeCanvas::OnMouse) + EVT_LEFT_DCLICK ( LifeCanvas::OnMouse) EVT_ERASE_BACKGROUND( LifeCanvas::OnEraseBackground) END_EVENT_TABLE() @@ -142,7 +156,7 @@ IMPLEMENT_APP(LifeApp) // ========================================================================== // some shortcuts -#define ADD_TOOL(id, bmp, tooltip, help) \ +#define ADD_TOOL(id, bmp, tooltip, help) \ toolBar->AddTool(id, bmp, wxNullBitmap, FALSE, -1, -1, (wxObject *)0, tooltip, help) @@ -184,32 +198,34 @@ LifeFrame::LifeFrame() : wxFrame((wxFrame *)0, -1, _("Life!"), wxPoint(200, 200) wxMenu *menuView = new wxMenu("", wxMENU_TEAROFF); wxMenu *menuGame = new wxMenu("", wxMENU_TEAROFF); - menuFile->Append(ID_RESET, _("Reset"), _("Start a new game")); - menuFile->Append(ID_SAMPLES, _("Sample game..."), _("Select a sample configuration")); + menuFile->Append(ID_NEW, _("&New"), _("Start a new game")); + menuFile->Append(ID_OPEN, _("&Open..."), _("Open an existing Life pattern")); + menuFile->Append(ID_SAMPLES, _("&Sample game..."), _("Select a sample configuration")); menuFile->AppendSeparator(); menuFile->Append(ID_ABOUT, _("&About...\tCtrl-A"), _("Show about dialog")); menuFile->AppendSeparator(); menuFile->Append(ID_EXIT, _("E&xit\tAlt-X"), _("Quit this program")); - menuView->Append(ID_SHOWNAV, _("Navigation toolbox"), _("Show or hide toolbox"), TRUE); + menuView->Append(ID_SHOWNAV, _("Navigation &toolbox"), _("Show or hide toolbox"), TRUE); menuView->Check (ID_SHOWNAV, TRUE); menuView->AppendSeparator(); - menuView->Append(ID_ORIGIN, _("Absolute origin"), _("Go to (0, 0)")); - menuView->Append(ID_CENTER, _("Center of mass"), _("Find center of mass")); - menuView->Append(ID_NORTH, _("North"), _("Find northernmost cell")); - menuView->Append(ID_SOUTH, _("South"), _("Find southernmost cell")); - menuView->Append(ID_EAST, _("East"), _("Find easternmost cell")); - menuView->Append(ID_WEST, _("West"), _("Find westernmost cell")); + menuView->Append(ID_ORIGIN, _("&Absolute origin"), _("Go to (0, 0)")); + menuView->Append(ID_CENTER, _("&Center of mass"), _("Find center of mass")); + menuView->Append(ID_NORTH, _("&North"), _("Find northernmost cell")); + menuView->Append(ID_SOUTH, _("&South"), _("Find southernmost cell")); + menuView->Append(ID_EAST, _("&East"), _("Find easternmost cell")); + menuView->Append(ID_WEST, _("&West"), _("Find westernmost cell")); menuView->AppendSeparator(); - menuView->Append(ID_ZOOMIN, _("Zoom &in\tCtrl-I")); - menuView->Append(ID_ZOOMOUT, _("Zoom &out\tCtrl-O")); + menuView->Append(ID_ZOOMIN, _("Zoom &in\tCtrl-I"), _("Zoom in")); + menuView->Append(ID_ZOOMOUT, _("Zoom &out\tCtrl-O"), _("Zoom out")); + menuView->Append(ID_INFO, _("&Description...\tCtrl-D"), _("View pattern description")); menuGame->Append(ID_START, _("&Start\tCtrl-S"), _("Start")); menuGame->Append(ID_STEP, _("&Next\tCtrl-N"), _("Single step")); menuGame->Append(ID_STOP, _("S&top\tCtrl-T"), _("Stop")); menuGame->Enable(ID_STOP, FALSE); menuGame->AppendSeparator(); - menuGame->Append(ID_TOPSPEED, _("Top speed!"), _("Go as fast as possible")); + menuGame->Append(ID_TOPSPEED, _("T&op speed!"), _("Go as fast as possible")); wxMenuBar *menuBar = new wxMenuBar(); menuBar->Append(menuFile, _("&File")); @@ -218,23 +234,30 @@ LifeFrame::LifeFrame() : wxFrame((wxFrame *)0, -1, _("Life!"), wxPoint(200, 200) SetMenuBar(menuBar); // tool bar - wxBitmap tbBitmaps[5]; + wxBitmap tbBitmaps[7]; tbBitmaps[0] = wxBITMAP(reset); - tbBitmaps[1] = wxBITMAP(play); - tbBitmaps[2] = wxBITMAP(stop); - tbBitmaps[3] = wxBITMAP(zoomin); - tbBitmaps[4] = wxBITMAP(zoomout); + tbBitmaps[1] = wxBITMAP(open); + tbBitmaps[2] = wxBITMAP(zoomin); + tbBitmaps[3] = wxBITMAP(zoomout); + tbBitmaps[4] = wxBITMAP(info); + tbBitmaps[5] = wxBITMAP(play); + tbBitmaps[6] = wxBITMAP(stop); wxToolBar *toolBar = CreateToolBar(); toolBar->SetMargins(5, 5); toolBar->SetToolBitmapSize(wxSize(16, 16)); - ADD_TOOL(ID_RESET, tbBitmaps[0], _("Reset"), _("Start a new game")); - ADD_TOOL(ID_START, tbBitmaps[1], _("Start"), _("Start")); - ADD_TOOL(ID_STOP, tbBitmaps[2], _("Stop"), _("Stop")); + + ADD_TOOL(ID_NEW, tbBitmaps[0], _("New"), _("Start a new game")); + ADD_TOOL(ID_OPEN, tbBitmaps[1], _("Open"), _("Open an existing Life pattern")); toolBar->AddSeparator(); - ADD_TOOL(ID_ZOOMIN, tbBitmaps[3], _("Zoom in"), _("Zoom in")); - ADD_TOOL(ID_ZOOMOUT, tbBitmaps[4], _("Zoom out"), _("Zoom out")); + ADD_TOOL(ID_ZOOMIN, tbBitmaps[2], _("Zoom in"), _("Zoom in")); + ADD_TOOL(ID_ZOOMOUT, tbBitmaps[3], _("Zoom out"), _("Zoom out")); + ADD_TOOL(ID_INFO, tbBitmaps[4], _("Description"), _("Show description")); + toolBar->AddSeparator(); + ADD_TOOL(ID_START, tbBitmaps[5], _("Start"), _("Start")); + ADD_TOOL(ID_STOP, tbBitmaps[6], _("Stop"), _("Stop")); + toolBar->Realize(); toolBar->EnableTool(ID_STOP, FALSE); // must be after Realize() ! @@ -344,33 +367,14 @@ void LifeFrame::UpdateUI() GetMenuBar()->GetMenu(1)->Enable(ID_ZOOMOUT, cellsize > 1); } -// event handlers +// Event handlers ----------------------------------------------------------- + +// OnMenu handles all events which don't have their own event handler void LifeFrame::OnMenu(wxCommandEvent& event) { switch (event.GetId()) { - case ID_START : OnStart(); break; - case ID_STEP : OnStep(); break; - case ID_STOP : OnStop(); break; - case ID_SHOWNAV : - { - bool checked = GetMenuBar()->GetMenu(1)->IsChecked(ID_SHOWNAV); - m_navigator->Show(checked); - break; - } - case ID_TOPSPEED: - { - m_running = TRUE; - m_topspeed = TRUE; - UpdateUI(); - while (m_running && m_topspeed) - { - OnStep(); - wxYield(); - } - break; - } - case ID_RESET: + case ID_NEW: { // stop if it was running OnStop(); @@ -386,23 +390,76 @@ void LifeFrame::OnMenu(wxCommandEvent& event) dialog.ShowModal(); break; } - case ID_EXIT : + case ID_EXIT: { // TRUE is to force the frame to close Close(TRUE); break; } + case ID_SHOWNAV : + { + bool checked = GetMenuBar()->GetMenu(1)->IsChecked(ID_SHOWNAV); + m_navigator->Show(checked); + break; + } + case ID_INFO: + { + wxString desc = m_life->GetDescription(); + + if ( desc.IsEmpty() ) + desc = _("Not available"); + + // should we make the description editable here? + wxMessageBox(desc, _("Description"), wxOK | wxICON_INFORMATION); + + break; + } + case ID_START : OnStart(); break; + case ID_STEP : OnStep(); break; + case ID_STOP : OnStop(); break; + case ID_TOPSPEED: + { + m_running = TRUE; + m_topspeed = TRUE; + UpdateUI(); + while (m_running && m_topspeed) + { + OnStep(); + wxYield(); + } + break; + } } } -void LifeFrame::OnClose(wxCloseEvent& WXUNUSED(event)) +void LifeFrame::OnOpen(wxCommandEvent& WXUNUSED(event)) { - // Stop if it was running; this is absolutely needed because - // the frame won't be actually destroyed until there are no - // more pending events, and this in turn won't ever happen - // if the timer is running faster than the window can redraw. - OnStop(); - Destroy(); + wxFileDialog filedlg(this, + _("Choose a file to open"), + _(""), + _(""), + _("Life patterns (*.lif)|*.lif|All files (*.*)|*.*"), + wxOPEN | wxFILE_MUST_EXIST); + + if (filedlg.ShowModal() == wxID_OK) + { + wxFileInputStream stream(filedlg.GetFilename()); + LifeReader reader(stream); + + // the reader handles errors itself, no need to do anything here + if (reader.IsOk()) + { + // stop if running and put the pattern + OnStop(); + m_life->Clear(); + m_life->SetPattern(reader.GetPattern()); + + // recenter canvas + m_canvas->Recenter(0, 0); + m_tics = 0; + UpdateInfoText(); + } + } } void LifeFrame::OnSamples(wxCommandEvent& WXUNUSED(event)) @@ -415,11 +472,11 @@ void LifeFrame::OnSamples(wxCommandEvent& WXUNUSED(event)) if (dialog.ShowModal() == wxID_OK) { - const LifeShape shape = dialog.GetShape(); + const LifePattern pattern = dialog.GetPattern(); - // put the shape + // put the pattern m_life->Clear(); - m_life->SetShape(shape); + m_life->SetPattern(pattern); // recenter canvas m_canvas->Recenter(0, 0); @@ -450,7 +507,7 @@ void LifeFrame::OnNavigate(wxCommandEvent& event) switch (event.GetId()) { - case ID_NORTH: c = m_life->FindNorth(); break; + case ID_NORTH: c = m_life->FindNorth(); break; case ID_SOUTH: c = m_life->FindSouth(); break; case ID_WEST: c = m_life->FindWest(); break; case ID_EAST: c = m_life->FindEast(); break; @@ -479,6 +536,16 @@ void LifeFrame::OnTimer(wxTimerEvent& WXUNUSED(event)) OnStep(); } +void LifeFrame::OnClose(wxCloseEvent& WXUNUSED(event)) +{ + // Stop if it was running; this is absolutely needed because + // the frame won't be actually destroyed until there are no + // more pending events, and this in turn won't ever happen + // if the timer is running faster than the window can redraw. + OnStop(); + Destroy(); +} + void LifeFrame::OnStart() { if (!m_running) @@ -820,17 +887,24 @@ void LifeCanvas::OnMouse(wxMouseEvent& event) msg.Printf(_("Cell: (%d, %d)"), i, j); ((LifeFrame *) wxGetApp().GetTopWindow())->SetStatusText(msg, 1); - // button pressed? + // NOTE that wxMouseEvent::LeftDown() and wxMouseEvent::LeftIsDown() + // have different semantics. The first one is used to signal that the + // button was just pressed (i.e., in "button down" events); the second + // one just describes the current status of the button, independently + // of the mouse event type. LeftIsDown is typically used in "mouse + // move" events, to test if the button is _still_ pressed. + + // is the button down? if (!event.LeftIsDown()) { m_status = MOUSE_NOACTION; return; } - // button just pressed? - if (m_status == MOUSE_NOACTION) + // was it pressed just now? + if (event.LeftDown()) { - // yes, update status and toggle this cell + // yes: start a new action and toggle this cell m_status = (m_life->IsAlive(i, j)? MOUSE_ERASING : MOUSE_DRAWING); m_mi = i; @@ -840,6 +914,7 @@ void LifeCanvas::OnMouse(wxMouseEvent& event) } else if ((m_mi != i) || (m_mj != j)) { + // no: continue ongoing action bool alive = (m_status == MOUSE_DRAWING); // prepare DC and pen + brush to optimize drawing diff --git a/demos/life/life.h b/demos/life/life.h index 0fa61a695c..75cd4d23a1 100644 --- a/demos/life/life.h +++ b/demos/life/life.h @@ -137,8 +137,9 @@ private: DECLARE_EVENT_TABLE() // event handlers - void OnSamples(wxCommandEvent& event); void OnMenu(wxCommandEvent& event); + void OnOpen(wxCommandEvent& event); + void OnSamples(wxCommandEvent& event); void OnNavigate(wxCommandEvent& event); void OnZoom(wxCommandEvent& event); void OnSlider(wxScrollEvent& event); diff --git a/demos/life/life.rc b/demos/life/life.rc index ae701642ed..269df77d17 100644 --- a/demos/life/life.rc +++ b/demos/life/life.rc @@ -2,13 +2,16 @@ mondrian ICON "mondrian.ico" #include "wx/msw/wx.rc" reset BITMAP "bitmaps/reset.bmp" +open BITMAP "bitmaps/open.bmp" play BITMAP "bitmaps/play.bmp" stop BITMAP "bitmaps/stop.bmp" zoomin BITMAP "bitmaps/zoomin.bmp" zoomout BITMAP "bitmaps/zoomout.bmp" +info BITMAP "bitmaps/info.bmp" north BITMAP "bitmaps/north.bmp" east BITMAP "bitmaps/east.bmp" south BITMAP "bitmaps/south.bmp" west BITMAP "bitmaps/west.bmp" center BITMAP "bitmaps/center.bmp" life BITMAP "bitmaps/life.bmp" + diff --git a/demos/life/makefile.b32 b/demos/life/makefile.b32 index 051d35b22f..a56b222798 100644 --- a/demos/life/makefile.b32 +++ b/demos/life/makefile.b32 @@ -10,7 +10,7 @@ WXDIR = $(WXWIN) TARGET=life -OBJECTS = $(TARGET).obj dialogs.obj game.obj +OBJECTS = $(TARGET).obj dialogs.obj game.obj reader.obj !include $(WXDIR)\src\makeprog.b32 diff --git a/demos/life/makefile.bcc b/demos/life/makefile.bcc index e7ac35af26..52b5acfd36 100644 --- a/demos/life/makefile.bcc +++ b/demos/life/makefile.bcc @@ -13,7 +13,7 @@ WXDIR = $(WXWIN) TARGET=life -OBJECTS=$(TARGET).obj dialogs.obj game.obj +OBJECTS=$(TARGET).obj dialogs.obj game.obj reader.obj !include $(WXDIR)\src\makeprog.bcc diff --git a/demos/life/makefile.dos b/demos/life/makefile.dos index c042c700cf..50e2bb53d4 100644 --- a/demos/life/makefile.dos +++ b/demos/life/makefile.dos @@ -11,7 +11,7 @@ WXDIR = $(WXWIN) TARGET=life -OBJECTS = $(TARGET).obj dialogs.obj game.obj +OBJECTS = $(TARGET).obj dialogs.obj game.obj reader.obj !include $(WXDIR)\src\makeprog.msc diff --git a/demos/life/makefile.g95 b/demos/life/makefile.g95 index 16127c981a..8f988b4a89 100644 --- a/demos/life/makefile.g95 +++ b/demos/life/makefile.g95 @@ -10,7 +10,8 @@ WXDIR = ../.. TARGET=life -OBJECTS = $(TARGET).o dialogs.o game.o +EXTRALDFLAGS=-Wl,--subsystem,console +OBJECTS = $(TARGET).o dialogs.o game.o reader.o include $(WXDIR)/src/makeprog.g95 diff --git a/demos/life/makefile.unx b/demos/life/makefile.unx index 8b8c3669d4..4fe657b60e 100644 --- a/demos/life/makefile.unx +++ b/demos/life/makefile.unx @@ -17,7 +17,7 @@ CC = gcc PROGRAM = life -OBJECTS = $(PROGRAM).o dialogs.o game.o +OBJECTS = $(PROGRAM).o dialogs.o game.o reader.o # implementation diff --git a/demos/life/makefile.vc b/demos/life/makefile.vc index 1f8314a8dd..c73905457d 100644 --- a/demos/life/makefile.vc +++ b/demos/life/makefile.vc @@ -12,7 +12,7 @@ WXDIR = $(WXWIN) PROGRAM=life -OBJECTS = $(PROGRAM).obj dialogs.obj game.obj +OBJECTS = $(PROGRAM).obj dialogs.obj game.obj reader.obj !include $(WXDIR)\src\makeprog.vc diff --git a/demos/life/makefile.wat b/demos/life/makefile.wat index 4ee7d9205c..4fd507ae4b 100644 --- a/demos/life/makefile.wat +++ b/demos/life/makefile.wat @@ -8,7 +8,7 @@ WXDIR = $(%WXWIN) PROGRAM = life -OBJECTS = $(PROGRAM).obj dialogs.obj game.obj +OBJECTS = $(PROGRAM).obj dialogs.obj game.obj reader.obj !include $(WXDIR)\src\makeprog.wat diff --git a/demos/life/reader.cpp b/demos/life/reader.cpp new file mode 100644 index 0000000000..8bb48ed375 --- /dev/null +++ b/demos/life/reader.cpp @@ -0,0 +1,91 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: reader.cpp +// Purpose: Life! pattern reader (writer coming soon) +// Author: Guillermo Rodriguez Garcia, +// Modified by: +// Created: Jan/2000 +// RCS-ID: $Id$ +// Copyright: (c) 2000, Guillermo Rodriguez Garcia +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ========================================================================== +// headers, declarations, constants +// ========================================================================== + +#ifdef __GNUG__ + #pragma implementation "reader.h" +#endif + +// For compilers that support precompilation, includes "wx/wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#ifndef WX_PRECOMP + #include "wx/wx.h" +#endif + +#include "wx/txtstrm.h" +#include "reader.h" + + +// ========================================================================== +// LifeReader +// ========================================================================== + +#define LIFE_CHECKVAL( msg ) \ + if (!m_ok) \ + { \ + wxMessageBox( msg, _("Error"), wxICON_EXCLAMATION | wxOK ); \ + return; \ + } + +LifeReader::LifeReader(wxInputStream& is) +{ + wxBufferedInputStream buff_is = wxBufferedInputStream(is); + wxTextInputStream text_is = wxTextInputStream(buff_is); + wxString line, rest; + + // check stream + m_ok = is.IsOk(); + LIFE_CHECKVAL(_("Couldn't read any data")); + + // read signature + m_ok = text_is.ReadLine().Contains(wxT("#Life 1.05")); + LIFE_CHECKVAL(_("Error reading signature. Not a Life pattern?")); + + // read description + m_description = wxT(""); + line = text_is.ReadLine(); + while (buff_is.IsOk() && line.StartsWith(wxT("#D"), &rest)) + { + m_description += rest.Trim(FALSE); + m_description += wxT("\n"); + line = text_is.ReadLine(); + } + + m_ok = buff_is.IsOk(); + LIFE_CHECKVAL(_("Unexpected EOF while reading description")); + + // read rules + m_ok = line.StartsWith(wxT("#N")); + LIFE_CHECKVAL(_("Sorry, non-conway rules not supported yet")); + + // read shape + while (buff_is.IsOk()) + { + line = ( text_is.ReadLine() ).Trim(); + + if (!line.IsEmpty()) + { + if (line.StartsWith(wxT("#P "), &rest)) + m_shape.Add(rest); + else + m_shape.Add(line); + } + } +} + diff --git a/demos/life/reader.h b/demos/life/reader.h new file mode 100644 index 0000000000..27a10af30e --- /dev/null +++ b/demos/life/reader.h @@ -0,0 +1,58 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: reader.h +// Purpose: Life! pattern reader (writer coming soon) +// Author: Guillermo Rodriguez Garcia, +// Modified by: +// Created: Jan/2000 +// RCS-ID: $Id$ +// Copyright: (c) 2000, Guillermo Rodriguez Garcia +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifndef _LIFE_READER_H_ +#define _LIFE_READER_H_ + +#ifdef __GNUG__ + #pragma interface "reader.h" +#endif + +// for compilers that support precompilation, includes "wx/wx.h" +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +// for all others, include the necessary headers +#ifndef WX_PRECOMP + #include "wx/wx.h" +#endif + +#include "game.h" + +// -------------------------------------------------------------------------- +// LifeReader +// -------------------------------------------------------------------------- + +class LifeReader +{ +public: + LifeReader(wxInputStream& is); + + inline bool IsOk() const { return m_ok; }; + inline wxString GetDescription() const { return m_description; }; + inline wxString GetRules() const { return m_rules; }; + inline wxArrayString GetShape() const { return m_shape; }; + inline LifePattern GetPattern() const + { + return LifePattern(_(""), m_description, m_rules, m_shape); + }; + +private: + bool m_ok; + wxString m_description; + wxString m_rules; + wxArrayString m_shape; +}; + +#endif // _LIFE_READER_H_ diff --git a/demos/life/samples.inc b/demos/life/samples.inc index b8e7f59761..63b6d820c2 100644 --- a/demos/life/samples.inc +++ b/demos/life/samples.inc @@ -23,9 +23,10 @@ * */ -const LifeShape g_shapes[] = +const LifePattern g_patterns[] = { - LifeShape( _("Glider"), + LifePattern( + _("Glider"), _("The glider is the first of a series of life forms, known " "as spaceships or fishes, which can travel along the game " "field retaining their original shape."), @@ -33,7 +34,8 @@ const LifeShape g_shapes[] = ".*." "..*" "***"), - LifeShape( _("Heavyweight spaceship"), + LifePattern( + _("Heavyweight spaceship"), _("The glider is just the smaller of the spaceships; this " "one, known as the heavyweight spaceship or 'big fish', " "is the largest spaceship which can travel alone without " @@ -44,7 +46,8 @@ const LifeShape g_shapes[] = "......*" "*.....*" ".******"), - LifeShape( _("Eater"), + LifePattern( + _("Eater"), _("An eater is any still life that can repair itself from " "some attacks. This one (bottom right), also known as " "'fishhook', eats gliders and fishes (spaceships) provided " @@ -60,7 +63,8 @@ const LifeShape g_shapes[] = "......*.*." "........*." "........**" ), - LifeShape( _("Dice shaker"), + LifePattern( + _("Dice shaker"), _("Oscillators have been extensively explored in Life!. " "The dice shaker turns around each seven tics; thus, it " "is an oscillator with a period of fourteen."), @@ -71,7 +75,8 @@ const LifeShape g_shapes[] = "*.*.*.*" "*.*.*.*" "**...**" ), - LifeShape( _("Hertz oscillator"), + LifePattern( + _("Hertz oscillator"), _("The Hertz oscillator is a good example of a set of life " "patterns known as 'billiard tables'. A billiard table is " "an oscillator which is built inside a stable border. In " @@ -88,7 +93,8 @@ const LifeShape g_shapes[] = ".............." ".......**....." ".......**....." ), - LifeShape( _("Phoenix"), + LifePattern( + _("Phoenix"), _("A phoenix is a pattern whose cells all die in every " "generation, and yet lives forever. For example, this is " "a phoenix with period two."), @@ -101,7 +107,8 @@ const LifeShape g_shapes[] = ".*......" "...*.*.." "...*...." ), - LifeShape( _("R-pentomino"), + LifePattern( + _("R-pentomino"), _("The R-pentomino is a methuselah - a life form which " "lives for hundreds of generations without stabilizing " "or dying. In particular, the R-Pentomino requires more " @@ -111,7 +118,8 @@ const LifeShape g_shapes[] = ".**" "**." ".*." ), - LifeShape( _("Thunderbird"), + LifePattern( + _("Thunderbird"), _("The thunderbird is another popular methuselah, which " "doesn't stabilize until the 243th generation. Note that " "because the initial configuration is symmetrical with " @@ -123,14 +131,16 @@ const LifeShape g_shapes[] = ".*." ".*." ".*." ), - LifeShape( _("Accorn"), + LifePattern( + _("Accorn"), _("Probably the most popular methuselah, the accorn lives " "for 5206 (!) generations."), 7, 3, ".*....." "...*..." "**..***" ), - LifeShape( _("Galaxy"), + LifePattern( + _("Galaxy"), _("One from my personal collection. It is really beautiful " "to see this configuration expand and shrink periodically " "for hundreds of tics before reaching a stable state."), @@ -148,7 +158,8 @@ const LifeShape g_shapes[] = "......*......" "......*......" ".......***..." ), - LifeShape( _("Glider gun"), + LifePattern( + _("Glider gun"), _("A gun is a stationary pattern that emits spaceships " "forever. The glider gun shown here was the first known " "gun, and indeed the first known finite pattern with " @@ -164,7 +175,8 @@ const LifeShape g_shapes[] = "**.........*...**........*.........." "............*.*....................." ".............*......................" ), - LifeShape( _("Puffer train"), + LifePattern( + _("Puffer train"), _("A puffer is an object that moves like a spaceship, except " "that it leaves a trail of debris behind. The puffer train " "is one of the best-known puffers. Originally found by " @@ -191,7 +203,8 @@ const LifeShape g_shapes[] = "....*" "*...*" ".****" ), - LifeShape( _("Max"), + LifePattern( + _("Max"), _("Max is the fastest-growing known pattern in Conway's Game " "of Life (possibly the fastest possible). It fills space to " "a density of 1/2, conjectured to be the maximum density, "