! ! The following procedures implement the Life simulation. They work by ! using each character in the buffer to store the intermediate states ! of the simulation; each "dead" space with a "live" neighbor is ! incremented throught the alphabet, starting with "a", and each ! live space is incremented through the numbers, starting from "0". ! When all of the spaces have been evaluated, each previously dead ! space that now contains a "c" (had 3 live neighbors) becomes alive, ! and each previously live space that now contains either a "3" or a "4" ! remains alive. All other cells become dead. ! ! Load the game into a buffer, compile the game and switch to an ! empty buffer. Use EVE to create the initial configuration. Any ! character other than a space will be considered a live cell. Note ! that TABs don't count as spaces, so don't use any! Now enter the ! command ! life ! and answer the question about the maximum numbers of generations, and ! watch it go. ! PROCEDURE go_horizontal (amount) LOCAL offset; offset := CURRENT_OFFSET; ! ! For now we can't go beyond the beginning of the line ! IF (offset = 0) AND (amount < 0) THEN RETURN 0; ENDIF; ! ! If we're going beyond the end of the line, add a space ! IF (offset + 1 = LENGTH (CURRENT_LINE)) AND (amount > 0) THEN MOVE_HORIZONTAL (1); COPY_TEXT (" "); MOVE_HORIZONTAL (-1); ELSE MOVE_HORIZONTAL (amount); ENDIF; RETURN 1; ENDPROCEDURE; ! go_horizontal PROCEDURE go_vertical (amount) LOCAL offset; ON_ERROR IF ERROR <> TPU$_NOEOBSTR THEN ! ! If at the end of the buffer, add a line ! IF ERROR = TPU$_ENDOFBUF THEN POSITION (SEARCH (LINE_END, FORWARD)); SPLIT_LINE; ELSE ! ! If at the beginning of the buffer, add a line ! IF ERROR = TPU$_BEGOFBUF THEN POSITION (SEARCH (LINE_BEGIN, REVERSE)); SPLIT_LINE; MOVE_VERTICAL (-1); ELSE ! ! Whatever it is that happened, we can't deal with it ! ABORT; ENDIF; ENDIF; ENDIF; ENDON_ERROR; ! ! Save where we are ! offset := CURRENT_OFFSET; MOVE_VERTICAL (amount); ! ! If we're no longer there, add the necessary spaces ! IF (offset <> CURRENT_OFFSET) OR (offset = LENGTH (CURRENT_LINE)) THEN offset := offset - CURRENT_OFFSET; COPY_TEXT (FAO ("!#* ", offset + 1)); MOVE_HORIZONTAL (-1); ENDIF; ENDPROCEDURE; ! go_vertical PROCEDURE evaluate_cell (cell_range) ! ! Evaluate the region around a cell ! LOCAL cell_mark; ! ! Start by dealing with the current row ! cell_mark := BEGINNING_OF (cell_range); evaluate_row (cell_mark); ! ! Deal with the preceding row, if we have one ! go_vertical (-1); evaluate_row (MARK (NONE)); POSITION (cell_mark); ! ! Deal with the following row, if we have one ! go_vertical (1); evaluate_row (MARK (NONE)); POSITION (cell_mark); ENDPROCEDURE; ! evaluate_cell PROCEDURE evaluate_row (cell_mark) ! ! Evaluate a single row ! LOCAL trans_range, end_mark, start_mark, status; status := go_horizontal (-1); start_mark := MARK (REVERSE); IF status THEN POSITION (cell_mark); ENDIF; status := go_horizontal (1); end_mark := MARK (REVERSE); IF status THEN POSITION (cell_mark); ENDIF; trans_range := CREATE_RANGE (start_mark, end_mark, reverse); TRANSLATE (trans_range, life_translate_out, life_translate_in); ENDPROCEDURE; ! evaluate_row PROCEDURE init_life LOCAL counter, in_string, out_string; ! ! Build the input string ! counter := 0; in_string := ''; LOOP in_string := in_string + ASCII (counter); counter := counter + 1; EXITIF counter > 255; ENDLOOP; ! ! Build the output string ! counter := 0; out_string := ''; LOOP CASE counter FROM 0 TO 255 [32]: out_string := out_string + ' '; [INRANGE]: out_string := out_string + '*'; ENDCASE; counter := counter + 1; EXITIF counter > 255; ENDLOOP; ! ! Translate the buffer contents ! TRANSLATE (CURRENT_BUFFER, out_string, in_string); ! ! Initialize various strings ! life_status := " LIFE Generation: !UL"; life_translate_in := ' abcdefg012345678'; life_translate_out := 'abcdefgh123456789'; ! ! Setup the status line and update the window ! SET (STATUS_LINE, CURRENT_WINDOW, REVERSE, FAO (life_status, 0)); UPDATE (CURRENT_WINDOW); ENDPROCEDURE; ! init_life PROCEDURE eve_life (input_generations) ! ! This procedure implements the Life "game". It works by using the buffer ! to store the state of the simulation, as we evaluate each cell. ! LOCAL cell_pattern, cell_range, current_gen, max_gen; ! ! Eat the "No string found" message ! ON_ERROR IF ERROR <> TPU$_STRNOTFOUND THEN ABORT ENDIF; ENDON_ERROR; IF NOT eve$prompt_number (input_generations, max_gen, 'Generations to run simulation: ', 'Aborting simulation') THEN RETURN; ENDIF; current_gen := 0; cell_pattern := ANY ('0123456789'); init_life; LOOP EXITIF current_gen >= max_gen; current_gen := current_gen + 1; TRANSLATE (CURRENT_BUFFER, '0', '*'); ! Prepare to evaluate the buffer POSITION (BEGINNING_OF (CURRENT_BUFFER)); LOOP cell_range := SEARCH (cell_pattern, FORWARD); EXITIF cell_range = 0; POSITION (cell_range); evaluate_cell (cell_range); POSITION (cell_range); go_horizontal (1); ENDLOOP; POSITION (BEGINNING_OF (CURRENT_BUFFER)); TRANSLATE (CURRENT_BUFFER, ! Prepare to display the buffer ' * ** ', ' abcdefgh0123456789'); SET (STATUS_LINE, CURRENT_WINDOW, REVERSE, FAO (life_status, current_gen)); UPDATE (CURRENT_WINDOW); ENDLOOP; MESSAGE ("Simulation Completed"); ENDPROCEDURE; ! eve_life PROCEDURE tpu$local_init eve$arg1_life := 'integer'; ENDPROCEDURE; tpu$local_init;