; Play Conway's Game of Life on a monochrome ST. This program was ; developed with the AssemPro assembler from Abacus Software. ; ; Designed and programmed by Eric Bergman-Terrell, 1987 ; ; Press left mouse button to quit the program. ; Press right mouse button to get a new cell generation. text ilabel c:\assemble\tos\tos.l ; Pixels in x-dimension y_pixels = 400 ; Pixels in y-dimension x_pixels = 640 ; Width of rectangle pix_x_len = 4 ; Height of rectangle pix_y_len = 4 ; Cells in x-dimension x_cells = x_pixels / pix_x_len ; Cells in y-dimension y_cells = y_pixels / pix_y_len start: gem_init ; Get a local stack for use by this program. lea stack_top, sp bsr init_gr ; Make the first generation of cells. restart: bsr randomize bsr init_old ; Plot the current generation to the screen. loop_2: bsr plot bsr new_to_old ; Generate the next generation. bsr update ; If right mouse button is pressed, quit. ; If left mouse button is pressed, create a new ; random generation. vq_mouse gr_handle, d0, d1, d2 and.w #3, d0 beq.s loop_2 and.w #1, d0 beq.s restart quit: gem_exit rts ; Copy new generation into old generation new_to_old: lea oldgen, a0 lea newgen, a1 lea oldend, a2 assign_lp: move.w (a1)+, (a0)+ cmp.l a2, a0 ble.s assign_lp rts ; Give the old generation an initial value totally different than ; the initial value of the new generation. init_old: lea oldgen, a0 lea oldend, a1 init_lp: move.b #2, (a0)+ cmp.l a1, a0 ble.s init_lp rts ; Generate a new generation of cells. For each nonempty cell, if it ; has two or three neighbors, it survives, otherwise it dies. If an ; empty cell has three neighbors, it becomes nonempty. A cell can ; have up to eight neighbors: ; ; ------- ; |N|N|N| ; ------- ; |N|*|N| * denotes a cell ; ------- N denotes a cell's neighbors ; |N|N|N| ; ------- ; update: lea oldgen - 1, a0 lea newgen - 1, a1 clr.w d0 ; x-coordinate clr.w d1 ; y-coordinate loop_5: addq.l #1, a0 addq.l #1, a1 clr.b d3 ; Compute number of oldgen[x, y]'s ; neighbors. ; Don't compute neighbors of a cell on a border. cmp.w #0, d0 beq update_cell cmp.w #0, d1 beq update_cell cmp.w #(x_cells - 1), d0 beq update_cell cmp.w #(y_cells - 1), d1 beq update_cell ; Count the neighbors of the current cell. move.l a0, a4 subq.l #1, a4 add.b (a4), d3 move.l a0, a4 addq.l #1, a4 add.b (a4), d3 move.l a0, a4 sub.l #(x_cells + 1), a4 add.b (a4)+, d3 add.b (a4)+, d3 add.b (a4), d3 move.l a0, a4 add.l #(x_cells - 1), a4 add.b (a4)+, d3 add.b (a4)+, d3 add.b (a4), d3 update_cell: tst.b (a0) beq.s empty cmp.b #2, d3 beq.s do_set cmp.b #3, d3 beq.s do_set bra.s do_clear do_set: move.b #1, (a1) bra.s next_x2 do_clear: clr.b (a1) bra.s next_x2 empty: cmp.b #3, d3 beq.s do_set bra.s do_clear next_x2: addq.w #1, d0 cmp.w #(x_cells - 1), d0 bgt.s next_y2 bra.s loop_5 next_y2: clr.w d0 addq.w #1, d1 cmp.w #(y_cells - 1), d1 bgt.s quit2 bra loop_5 quit2: rts ; Prepare to plot to screen. init_gr: vs_clip gr_handle, #1, px vswr_mode gr_handle, #1, d0 vsf_color gr_handle, #1, d0 vsl_color gr_handle, #1, d0 v_hide_c gr_handle ; Make sure that rectangle perimeters are not drawn. vsf_perimeter gr_handle, #0, d0 bsr clear rts ; Clear the screen. clear: vsf_interior gr_handle, #8, d1 lea pxy_array, a3 clr.w (a3)+ clr.w (a3)+ move.w #(x_pixels - 1), (a3)+ move.w #(y_pixels - 1), (a3) v_bar gr_handle, pxy_array rts ; Generate a random cell pattern. randomize: lea newgen, a3 lea newend, a4 loop: random move.w d0, d3 and.w #7, d3 asr.b d3, d0 and.l #1, d0 move.b d0, (a3)+ cmp.l a4, a3 bgt.s trim bra.s loop ; Remove cells from the border of the rectangle. trim: lea newgen, a3 subq.l #1, a3 clr.w d0 ; x-coordinate clr.w d1 ; y-coordinate ; Clear all cells on borders. trim_loop: addq.l #1, a3 tst.w d0 beq clear_cell cmp.w #(x_cells - 1), d0 beq clear_cell cmp.w #0, d1 beq clear_cell cmp.w #(y_cells - 1), d1 beq clear_cell next_x_2: addq.w #1, d0 cmp.w #(x_cells - 1), d0 bgt.s next_y_2 bra.s trim_loop next_y_2: clr.w d0 addq.w #1, d1 cmp.w #(y_cells - 1), d1 bgt.s return_3 bra trim_loop return_3: rts ; Remove one cell from a border of the rectangle. clear_cell: clr.b (a3) bra.s next_x_2 ; Plot a cell pattern to the screen. plot: lea newgen, a0 lea oldgen, a2 clr.w d0 ; x-coordinate clr.w d1 ; y-coordinate draw_loop: clr.w d3 move.b (a0)+, d3 move.b (a2)+, d4 cmp.b d3, d4 beq next_x ; Draw the rectangle. lea pxy_array, a1 move.w d0, (a1)+ move.w d1, (a1)+ move.w d0, d5 move.w d1, d6 addq.w #(pix_x_len - 1), d5 addq.w #(pix_y_len - 1), d6 move.w d5, (a1)+ move.w d6, (a1) ; Save registers. movem.l d0-d3/a0-a2, -(sp) vsf_interior gr_handle, d3, d2 v_bar gr_handle, pxy_array ; Restore registers. movem.l (sp)+, d0-d3/a0-a2 next_x: addq.w #pix_x_len, d0 cmp.w #x_pixels, d0 bge.s next_y bra draw_loop next_y: clr.w d0 addq.w #pix_y_len, d1 cmp.w #y_pixels, d1 bge.s return_2 bra draw_loop return_2: rts data align newgen: ds.b (x_cells * y_cells) align newend: ds.b 0 align oldgen: ds.b (x_cells * y_cells) align oldend: ds.b 0 align pxy_array: ds.w 4 px: dc.w 0, 0, x_pixels, y_pixels stack_bot: ds.w 512 stack_top: ds.b 0 end