Kirjoitttelin sadepäivänä tylsyyttäni yksinkertaisen GUI version perinteisestä "Game Of Life" ohjelmasta. Tuohon ehkä pitäisi jokunen toiminnallisuus ja kontrolli vielä lisätä sekä tuki hiirellä skrollaamiseen.
EDIT: lisätty tuki liikkumiseen hiirellä raahaamalla.
Käyttää map tietorakennetta solujen tallentamiseen taulukon sijaan, joten pelkät elossa olevat solut tallennetaan. Bonuksena nuolinäppäimillä voi vapaasti liikkua ilman rajoituksia ja seurata "elämän" kehittymistä.
\
\ Game Of Life
\
needs nk/gui
24 font:system font:new "font1" font:atlas! drop
100 constant MIN-DELAY
1000 constant MAX-DELAY
16 constant STEP-X
16 constant STEP-Y
53 constant ROWS
53 constant COLS
nullvar update-task-id
var delay
var population
: create-cell \ m a -- m
dup "%d:%d" s:strfmt m:_! ;
: neighbours? \ a -- a
>r m:new
[
[-1,-1],[0,-1],[1,-1],
[-1,0],[1,0],
[-1,1],[0,1],[1,1]
] ( r@ ' n:+ a:2map ) a:map rdrop
' create-cell a:each! drop ;
: count-alive-neighbours \ m a -- m n
neighbours? m:keys nip m:@ ( null? not nip ) a:filter a:len nip ;
: evolve \ m -- m
m:new m:new rot m:vals
(
dup>r count-alive-neighbours dup 2 n:= swap 3 n:= or if
over r@ create-cell drop
then
r> neighbours?
(
4 pick rot m:exists? !if
swap dup>r create-cell drop
r@ count-alive-neighbours 3 n:= if
over r> create-cell drop
else
rdrop
then
else
2drop
then
) m:each drop
) a:each! 2drop nip ;
: populate-random \ m -- m
( >r
( rand-pcg 100 n:mod 15 n:> !if
r@ 2 a:close create-cell
else
drop
then
) 0 COLS n:1- loop rdrop
) 0 ROWS n:1- loop ;
: grid-widget \ m --
nk:widget nk:WIDGET_INVALID n:= !if
{ rows: @ROWS, cols: @COLS } nk:layout-grid-begin
( >r
(
dup 1 r@ 1 nk:grid nk:BUTTON_LEFT swap true nk:clicked? if
dup r@ 2 a:close
"y-offs" nk:get "x-offs" nk:get 2 a:close
' n:- a:2map
"pressed" swap nk:set
then
dup 1 r@ 1 nk:grid nk:hovered? nk:BUTTON_LEFT nk:down? and if
dup r@ 2 a:close "down" swap nk:set
then
tuck "y-offs" nk:get n:+ r@ "x-offs" nk:get n:+ "%d:%d" s:strfmt m:exists? if
swap 1 r@ 1 nk:grid -1 nk:rect-shrink 0 "black" nk:fill-rect
else
swap 1 r@ 1 nk:grid 0 2 "black" nk:stroke-rect
then
) 0 ROWS n:1- loop rdrop
) 0 COLS n:1- loop
nk:layout-grid-end drop
"pressed" nk:get null? if
drop
else
"down" nk:get swap ' n:- a:2map
a:open
"x-offs" swap nk:set
"y-offs" swap nk:set
then
nk:BUTTON_LEFT nk:down? !if
"pressed" null nk:set
then
else
drop
then ;
: reset
m:new populate-random population !
"x-offs" 0 nk:set
"y-offs" 0 nk:set
null nk:do ;
: new-win
{
name: "main",
wide: 600,
high: 610,
resizable: false,
bg: "white",
title: "Game Of Life"
} nk:win ;
: handle-timer
d:msec >r "msecs" nk:get null? !if
r@ swap n:- delay @ n:< !if
"msecs" r> nk:set
population @ evolve population !
else
rdrop
then
else
drop "msecs" r> nk:set
then ;
: handle-keys
nk:KEY_LEFT nk:key-released? if "x-offs" dup nk:get STEP-X n:- nk:set then
nk:KEY_RIGHT nk:key-released? if "x-offs" dup nk:get STEP-X n:+ nk:set then
nk:KEY_UP nk:key-released? if "y-offs" dup nk:get STEP-Y n:- nk:set then
nk:KEY_DOWN nk:key-released? if "y-offs" dup nk:get STEP-Y n:+ nk:set then ;
: main-render
delay @
{
bg: "white",
flags: [ @nk:WINDOW_NO_SCROLLBAR ],
x-offs: 0,
y-offs: 0
}
nk:begin
null { rows: [0.90,0.10], cols: 1, rgap: 4, cgap:4, margin: 4 } nk:layout-grid-begin
0 1 0 1 nk:grid nk:rect>local nk:grid-push population @ grid-widget
1 1 0 1 nk:grid { rows: 1, cols: 8, rgap: 4, cgap:4, margin: 4 } nk:layout-grid-begin
0 1 0 1 nk:grid nk:rect>local nk:grid-push "Reset" ' reset nk:button-label
0 1 1 7 nk:grid nk:rect>local nk:grid-push MIN-DELAY MAX-DELAY 1 delay true nk:slider
nk:layout-grid-end
1 1 0 1 nk:grid 4 2 "black" nk:stroke-rect
nk:layout-grid-end
handle-keys
handle-timer
nk:end
\ Old animation step delay value is on TOS, was it changed?
delay @ n:= !if
update-task-id @ t:notify
then ;
: update-task
repeat
null nk:do
delay @ 1000 n:/ sleep
again ;
: init
MIN-DELAY delay !
m:new populate-random population !
1500k 1500k nk:max-vertex-element ;
: app:main
init
' update-task t:task update-task-id !
new-win ' main-render -1 nk:render-loop ;Aihe on jo aika vanha, joten et voi enää vastata siihen.