import text.jrt import keys.jrt import random.jrt : !+ ( v p -- ) dup @ = swap boardh @ < and swap dup 0 >= swap boardw @ < and and ; 0x80 const FMINE 0x40 const FREVEALED 0x20 const FFLAG 0x0F const NEIGHBOUR-MASK : place-mine ( x y -- f ) square-at dup b@ FMINE & not if FMINE swap b! 0 then not ; : rand-mine ( -- ) begin rand boardw @ % rand boardh @ % place-mine until ; : reset-board board begin dup board-lim < while 0 over b! 1+ repeat drop ; : populate-board minecount @ begin rand-mine 1- dup not until drop ; : mine? ( p -- f ) b@ FMINE & ; : flag? ( p -- f ) b@ FFLAG & ; : revealed? ( p -- f ) b@ FREVEALED & ; : squarecount ( p -- c ) b@ NEIGHBOUR-MASK & ; : do-at ( x y cp -- ) >rot 2dup valid-pos? if square-at swap execute else drop drop drop then ; : do-neighbour-squares ( x y cp -- ) >r over 1- over 1- r@ do-at over 1- over r@ do-at over 1- over 1+ r@ do-at over over 1- r@ do-at over over 1+ r@ do-at over 1+ over 1- r@ do-at over 1+ over r@ do-at swap 1+ swap 1+ t >t >t >t >t >t DOES} theme ! ; ( cursor grid block mine flag bg ) blue white black magenta red lgray deftheme win31 white yellow black lmagenta yellow red deftheme hotdog yellow lgray cyan lmagenta yellow blue deftheme borland magenta lgray magenta magenta magenta cyan deftheme cga4 win31 ( minesweeper board drawing ) : draw-neighbour-count ( b -- ) NEIGHBOUR-MASK & dup col-count dup if [ key 0 lit ] + else drop [ key lit ] then draw-char ; : draw-flag ( -- ) col-flag 0x0d draw-char ; : draw-mine ( -- ) col-mine 0xec draw-char ; : draw-block ( -- ) col-block 0xb1 draw-char ; : draw-revealed ( b -- ) dup FMINE & if draw-mine drop else draw-neighbour-count then ; : draw-hidden ( b -- ) FFLAG & if draw-flag else draw-block then ; : draw-square ( p -- ) b@ dup FREVEALED & if draw-revealed else draw-hidden then col-grid ; : boardx ( -- x ) pagew boardw @ 2* 1+ - 2/ ; : boardy ( -- y ) pageh boardh @ 2* 1+ - 2/ ; : boardx! ( -- ) boardx textx! ; : boardy! ( -- ) boardy texty! ; : next-row ( -- ) nextline boardx! ; : draw-border ( end mid -- ) boardw @ begin .- 1- dup while over execute repeat drop drop execute next-row ; : draw-board-top tl ' tr ' dT draw-border ; : draw-board-bottom bl ' br ' uT draw-border ; : draw-rowborder rT ' lT ' .+ draw-border ; : draw-row ( p -- p ) .| begin dup draw-square .| 1+ dup square-pos drop not until next-row ; : draw-board ( -- ) 0 boxstyle! col-grid col-bg boardx! boardy! draw-board-top board begin draw-row dup square-pos valid-pos? while draw-rowborder repeat drop draw-board-bottom ; ( general-purpose drawing ) : clear [ key lit ] fill-page ; : emptych? ( ch -- f ) dup 32 = swap 0 = or ; : drawdot? ( st -- f ) dup b@ emptych? swap 1+ b@ emptych? or not ; : dot 7 draw-char ; : sp 32 draw-char ; : spacer ( st -- ) sp drawdot? if dot else sp then sp ; : draw-spaced-text ( st -- ) begin dup b@ dup while draw-char dup spacer 1+ repeat drop drop ; ( menu subsystem ) 2 cells const menu-optsize var current-menu : menu-options current-menu @ cell + 1+ ; : menu-size current-menu @ cell + b@ ; : init-menu current-menu @ @ execute ; : menu-option ( iopt -- p ) menu-optsize * menu-options + ; 0 var, menu-selected : menu-activate menu-selected @ menu-option cell + @ execute ; : menu-selected! ( i -- ) dup 0 >= over menu-size < and if menu-selected ! else drop then ; : menu-selected+! ( di -- ) menu-selected @ + menu-selected! ; : draw-selection ( iopt -- ) menu-selected @ = if draw-mine else sp then sp ; : draw-option ( iopt -- ) white fg! menu-option @ draw-text ; : draw-menu 30 9 textxy! textx 0 begin dup menu-size < while dup draw-selection dup draw-option 1+ nextline over textx! repeat drop drop ; : await-menu wait-key key>scan dup %esc = if leave then dup %up = if -1 menu-selected+! then dup %down = if 1 menu-selected+! then %enter = if menu-activate init-menu then ; : run-menu enter init-menu begin draw-menu await-menu in-progress? not until uncancel ; { :timm defmenu ( itemcount cpinit -- ) CREATE target current-menu !t w>t dup >t menu-optsize * ALLOT DOES} menu-selected @ >r current-menu @ >r current-menu ! 0 menu-selected! run-menu rot !t cell + !t ; } ( minesweeper game UI ) 0 bvar, cursx 0 bvar, cursy : draw-cursor ( -- ) 1 boxstyle! col-curs cursx b@ 2* boardx + textx! cursy b@ 2* boardy + texty! textx tl .- tr nextline textx! textx .| dup 2 + textx! .| nextline textx! bl .- br ; : move-cursor ( dx dy -- ) cursy b@ + swap cursx b@ + swap 2dup valid-pos? if cursy b! cursx b! else drop drop then ; : curs@ cursx b@ cursy b@ ; 0x21 const %f : await-command wait-key key>scan dup %esc = if leave then dup %left = if -1 0 move-cursor then dup %right = if 1 0 move-cursor then dup %up = if 0 -1 move-cursor then dup %down = if 0 1 move-cursor then dup %f = if curs@ flag-at then dup %enter = swap %space = or if curs@ reveal-at then ; : popupbox ( h -- ) 20 8 textxy! 0 hstyle! 1 vstyle! 39 swap filled draw-box ; : result-message ( st x -- ) 5 popupbox ( x ) 10 textxy! draw-spaced-text wait-key drop ; : display-result game-state b@ dup WON = if green bg! lcyan fg! s" YOU WON" 26 result-message then LOST = if red bg! yellow fg! s" YOU LOST" 25 result-message then ; 2 :noname blue bg! lgray fg! 4 popupbox ; defmenu quitmenu ' leave s" Return to game" 0 defitem :noname QUIT game-state b! ; s" Quit to title" 1 defitem : confirm-quit cancelled? if quitmenu then ; : draw-game draw-board draw-cursor ; : play enter col-bg clear begin draw-game await-command confirm-quit in-progress? not until draw-board display-result enter ; : start init-board play ; ( title menu ) array title-text t", SWINE MEEPER" 5 :noname col-bg clear ; defmenu theme-menu ' win31 s" 3.11 for Worksties" 0 defitem ' hotdog s" Pork Sausage Stand" 1 defitem ' borland s" Boarland Turbohog" 2 defitem ' cga4 s" Sowlo Jazz" 3 defitem ' leave s" Done" 4 defitem 20 12 30 minecount ! boardh ! boardw ! : config-game ( boardw boardh minecount -- ) minecount ! boardh ! boardw ! leave ; 3 :noname red bg! clear ; defmenu difficulty-menu :noname 10 10 10 config-game ; s" Easy ( 10x10, 10 swine )" 0 defitem :noname 20 12 30 config-game ; s" Moderate ( 20x12, 30 swine )" 1 defitem :noname 30 12 60 config-game ; s" Hard ( 30x12, 60 swine )" 2 defitem : draw-title blue bg! yellow fg! clear 17 3 textxy! title-text draw-spaced-text ; 4 ' draw-title defmenu title-menu ' start s" Start Game" 0 defitem ' difficulty-menu s" Difficulty" 1 defitem ' theme-menu s" Themes" 2 defitem ' leave s" Quit" 3 defitem : title textmode reseed! hidecursor title-menu textmode ; ' title ' main redefine { s" swine.com" writecom }