lifedemo = proc () qi = sequence[int] ai = array[int] ab = array[bool] pwidth = 8 bwidth: int := int$parse(xdemo_default("life", "BorderWidth")) except when not_found, overflow, bad_format: bwidth := 2 end back: x_pixmap := x_display$white() bdr: x_pixmap := x_display$black() backpix: int := WhitePixel forepix: int := BlackPixel mousepix: int := BlackPixel if x_display$cells() > 2 then begin r, g, b: int := x_parse_color(xdemo_default("life", "Border")) bdr := x_pixmap$tile(x_display$alloc_color(r, g, b)) end except when not_found: end begin r, g, b: int := x_parse_color(xdemo_default("life", "Background")) backpix := x_display$alloc_color(r, g, b) back := x_pixmap$tile(backpix) end except when not_found: end begin r, g, b: int := x_parse_color(xdemo_default("life", "Foreground")) forepix := x_display$alloc_color(r, g, b) mousepix := forepix end except when not_found: end begin r, g, b: int := x_parse_color(xdemo_default("life", "Mouse")) mousepix := x_display$alloc_color(r, g, b) end except when not_found: end end f: x_font := x_font$create("8x13") w: x_window, cwidth, cheight: int := x_tcons("life", back, bdr, xdemo_geometry(), "=40x40+1+1", f, 8, 8, 1, 3, 3, bwidth) x_font$destroy(f) x_window$set_resize(w, 1, 8, 1, 8) w.name := "life" w.input := ButtonPressed + UnmapWindow x_window$map(w) w.input := ButtonPressed + ExposeRegion + UnmapWindow cr: x_cursor := x_cursor$scons(arrow_width, arrow_height, arrow, arrow_mask, backpix, mousepix, arrow_x, arrow_y, GXcopy) w.cursor := cr stopped: bool := false ev: event := x_input$empty_event() while true do sx, sy, width, height, bw, ms, wk: int, iw: x_window := x_window$query(w) if height <= 30 cor width <= 30 then x_window$destroy(w) return end x_window$clear(w) width := (width - 1) / pwidth prob: int := int$min(10, width / 2) height := (height - 1) / pwidth + 2 span: int := width * height arena: ab := ab$fill(0, span, false) xcoords: ai := ai$fill(0, span, 0) ycoords: ai := ai$fill(0, span, 0) for point: int in int$from_to(0, span - 1) do xcoords[point] := (point // width) * pwidth + 1 ycoords[point] := (point / width - 1) * pwidth + 1 end neighbor_list: ai := ai$predict(1, span / 4) neighbors: ai := ai$fill(0, span, 0) neighbor_map: ai := ai$fill(0, span, 0) generation: int := 1 offset: qi := qi$[-(width + 1), -width, -(width - 1), -1, 1, width - 1, width, width + 1] change_sets: ai := ai$predict(1, span) change_clears: ai := ai$predict(1, span) span := span - width while true do while stopped cor (ai$empty(change_sets) cand ai$empty(change_clears)) cor x_input$pending() do x_input$deq(ev) if ev.kind = UnmapWindow then x_input$deq(ev) end if ev.kind = ButtonPressed cand ev.value = LeftButton then for point: int in int$from_to(width, span - 1) do if random$next(prob) ~= 0 then continue end if neighbor_map[point] ~= generation then neighbor_map[point] := generation ai$addh(neighbor_list, point) end if arena[point] then ai$addh(change_clears, point) else ai$addh(change_sets, point) end end break elseif ev.kind = ButtonPressed cand ev.value = MiddleButton then stopped := ~stopped elseif ev.kind = ButtonPressed cand ev.value = RightButton then for i: int in int$from_to(0, span - 1) do arena[i] := false neighbors[i] := 0 neighbor_map[i] := 0 end generation := 1 x_window$clear(w) ai$trim(change_sets, 1, 0) ai$trim(change_clears, 1, 0) elseif ev.kind = ExposeWindow cand (width ~= (ev.x - 1) / pwidth cor height ~= (ev.y - 1) / pwidth + 2) then exit changed else x1: int := ev.x y1: int := ev.y x: int := (x1 + ev.x0 - 1) / pwidth y: int := (y1 + ev.y0 - 1) / pwidth x1 := x1 / pwidth y1 := y1 / pwidth for i: int in int$from_to(x1, x) do for j: int in int$from_to(y1, y) do point: int := j * width + i if arena[point] then x_window$pix_set(w, forepix, xcoords[point], ycoords[point], pwidth - 1, pwidth - 1) end except when bounds: end end end end end for point: int in ai$elements(change_clears) do x_window$pix_set(w, backpix, xcoords[point], ycoords[point], pwidth - 1, pwidth - 1) arena[point] := false for i: int in qi$elements(offset) do begin index: int := point + i neighbors[index] := neighbors[index] - 1 if neighbor_map[index] ~= generation then neighbor_map[index] := generation ai$addh(neighbor_list, index) end end except when bounds: end end end ai$trim(change_clears, 1, 0) for point: int in ai$elements(change_sets) do x_window$pix_set(w, forepix, xcoords[point], ycoords[point], pwidth - 1, pwidth - 1) arena[point] := true for i:int in qi$elements(offset) do begin index: int := point + i neighbors[index] := neighbors[index] + 1 if neighbor_map[index] ~= generation then neighbor_map[index] := generation ai$addh(neighbor_list, index) end end except when bounds: continue end end end ai$trim(change_sets, 1, 0) generation := generation + 1 for point: int in ai$elements(neighbor_list) do n: int := neighbors[point] if n = 3 then if ~arena[point] cand point >= width cand point < span then ai$addh(change_sets, point) end elseif n ~= 2 then if arena[point] then ai$addh(change_clears, point) end end end ai$trim(neighbor_list, 1, 0) end except when changed: end end end lifedemo