USING: accessors arrays calendar colors combinators.short-circuit fonts kernel literals math math.matrices math.order math.vectors namespaces opengl random ranges sequences timers ui ui.commands ui.gadgets ui.gadgets.worlds ui.gestures ui.pens.solid ui.render ui.text ; IN: snake CONSTANT: CELLS 40 CONSTANT: SCREEN-SIZE 400 TUPLE: player pos dir len ; TUPLE: snake-gadget < gadget grid player game-over? timer ; SYMBOLS: :empty :apple :snake ; SYMBOLS: :up :down :left :right ; : initial-state ( gadget -- gadget ) CELLS CELLS :empty >>grid player new { 20 20 } >>pos { :up :down :left :right } random >>dir 1 >>len >>player 10 . f >>game-over? ; DEFER: on-tick : ( -- gadget ) snake-gadget new initial-state COLOR: gray50 >>interior dup '[ _ on-tick ] f 16667 microseconds >>timer ; M: snake-gadget pref-dim* drop ${ SCREEN-SIZE SCREEN-SIZE } ; M:: snake-gadget draw-gadget* ( SNAKE -- ) COLOR: red gl-color SNAKE player>> pos>> 10 v*n { 10 10 } gl-fill-rect ; :: on-tick ( GADGET -- ) GADGET relayout-1 ; :: move-up ( GADGET -- ) GADGET player>> pos>> { 0 -1 } v+ :> c GADGET player>> c >>pos drop ; : print-10 ( g -- ) drop 10 . ; snake-gadget "gestures" f { { T{ key-down { sym "UP" } } print-10 } ! { T{ key-down { sym "DOWN" } } move-down } ! { T{ key-down { sym "LEFT" } } move-left } ! { T{ key-down { sym "RIGHT" } } move-right } ! { T{ key-down { sym " " } } new-game } } define-command-map MAIN-WINDOW: snake-window { { title "SNAKE" } { window-controls { normal-title-bar close-button minimize-button } } } >>gadgets ;