Recent Posts

Pages: 1 ... 8 9 [10]
91
Open Forum / Re: AllBASIC Forum
« Last post by Gemino Smothers on November 25, 2023, 08:53:40 PM »
People are going through a lot in these times. Hopefully one day, there will be a great return to computing.

There's not much for me to share other than my language experiments. It's just nice to just have a place to keep the option for discussion open.

My forum has been equally as dead. I just post progress updates. From what I have seen other forums are toxic gossip cesspools and are also dying. The only options are to let forums die or be the ones to weather the storm.
92
Open Forum / AllBASIC Forum
« Last post by John on November 12, 2023, 11:16:09 AM »
Forum Members,

Is there any topic the members of this forum would be interested in? With AIR going MIA and very little activity by anyone other than myself, I'm considering closing down the forum. The forum and archive forums I host are well indexed in the search engines and is the only thing at this point that justifies keeping the forums active.

Does anyone have a suggestion how we may see more activity on the forum?




 
93
Interpreters / Re: Net Basic - a BASIC in PHP
« Last post by John on October 05, 2023, 08:44:49 PM »
I have a remote socket based console debugger that works with the ScriptBasic web server.

https://allbasic.info/forum/index.php?topic=393.msg4317#msg4317
94
Interpreters / Re: Net Basic - a BASIC in PHP
« Last post by Gemino Smothers on October 05, 2023, 07:28:08 PM »
I need to keep Script Basic in mind as a web programming language.. Server side scripting and all.
95
Interpreters / Re: Net Basic - a BASIC in PHP
« Last post by John on October 05, 2023, 04:20:45 PM »
Nice feature!

Control Solutions uses ScriptBasic in a few of their controllers. It has a web interface based interpreter as well.



96
Interpreters / Net Basic - a BASIC in PHP
« Last post by Gemino Smothers on October 05, 2023, 01:54:40 PM »
I have been working on another project. What do you think about it? A Tiny BASIC direct interpreter online service in PHP.

A direct interpreter hosted on the web. You submit code and get results. There's no input, but GET requests may be read to allow url variables and forms.

Programs may be compiled/embedded into a url. Visit https://www.lucidapogee.com/netbasic and copy/paste/run some of the examples. Whenever you run code on the page, you get program encoded urls. One for HTTPS and one for HTTP. The whole site is available to HTTPS or HTTP through a subdomain.

Here's some examples:

Code: [Select]
1 REM https://rosettacode.org/wiki/Attractive_numbers
10 FOR x = 1 TO 120
20 LET n = x
30 LET c = 0
40 IF n MOD 2 <> 0 THEN 70
50 LET n = INT(n / 2)
60 LET c = c + 1
70 IF n MOD 2 = 0 THEN 40
80 FOR i = 3 TO SQR(n) STEP 2
90 IF n MOD i <> 0 THEN 120
100 LET n = INT(n / i)
110 LET c = c + 1
120 IF n MOD i = 0 THEN 90
130 NEXT i
140 IF n <= 2 THEN 160
150 LET c = c + 1
160 IF NOT(PRIME(c)) THEN 180
170 PRINT x,
180 NEXT x
Program encoded url: https://www.lucidapogee.com/netbasic/?listing=1%20REM%20https%3A%2F%2Frosettacode.org%2Fwiki%2FAttractive_numbers%0D%0A10%20FOR%20x%20%3D%201%20TO%20120%0D%0A20%20LET%20n%20%3D%20x%0D%0A30%20LET%20c%20%3D%200%0D%0A40%20IF%20n%20MOD%202%20%3C%3E%200%20THEN%2070%0D%0A50%20LET%20n%20%3D%20INT%28n%20%2F%202%29%0D%0A60%20LET%20c%20%3D%20c%20%2B%201%0D%0A70%20IF%20n%20MOD%202%20%3D%200%20THEN%2040%0D%0A80%20FOR%20i%20%3D%203%20TO%20SQR%28n%29%20STEP%202%0D%0A90%20IF%20n%20MOD%20i%20%3C%3E%200%20THEN%20120%0D%0A100%20LET%20n%20%3D%20INT%28n%20%2F%20i%29%0D%0A110%20LET%20c%20%3D%20c%20%2B%201%0D%0A120%20IF%20n%20MOD%20i%20%3D%200%20THEN%2090%0D%0A130%20NEXT%20i%0D%0A140%20IF%20n%20%3C%3D%202%20THEN%20160%0D%0A150%20LET%20c%20%3D%20c%20%2B%201%0D%0A160%20IF%20NOT%28PRIME%28c%29%29%20THEN%20180%0D%0A170%20PRINT%20x%2C%0D%0A180%20NEXT%20x

Code: [Select]
1 REM https://rosettacode.org/wiki/Nth_root
10 LET a = INT(RND * 5999) + 2
20 PRINT "nth root of "; a; "..."
30 FOR n = 1 TO 10
40 LET p = .00001
50 LET x = a
60 LET y = a / n
70 IF ABS(x - y) <= p THEN 110
80 LET x = y
90 LET y = ((n - 1) * y + a / y ^ (n - 1)) / n
100 IF ABS(x - y) > p THEN 80
110 PRINT n; " : "; y
120 NEXT n
Program encoded url: https://www.lucidapogee.com/netbasic/?listing=10%20LET%20a%20%3D%20INT%28RND%20%2A%205999%29%20%2B%202%0D%0A20%20PRINT%20%22nth%20root%20of%20%22%3B%20a%3B%20%22...%22%0D%0A30%20FOR%20n%20%3D%201%20TO%2010%0D%0A40%20LET%20p%20%3D%20.00001%0D%0A50%20LET%20x%20%3D%20a%0D%0A60%20LET%20y%20%3D%20a%20%2F%20n%0D%0A70%20IF%20ABS%28x%20-%20y%29%20%3C%3D%20p%20THEN%20110%0D%0A80%20LET%20x%20%3D%20y%0D%0A90%20LET%20y%20%3D%20%28%28n%20-%201%29%20%2A%20y%20%2B%20a%20%2F%20y%20%5E%20%28n%20-%201%29%29%20%2F%20n%0D%0A100%20IF%20ABS%28x%20-%20y%29%20%3E%20p%20THEN%2080%0D%0A110%20PRINT%20n%3B%20%22%20%3A%20%22%3B%20y%0D%0A120%20NEXT%20n

Code: [Select]
1 REM https://rosettacode.org/wiki/Prime_decomposition
10 LET loops = 100
20 FOR x = 1 TO loops
30 LET n = x
40 PRINT n; " : ";
50 LET c = 0
60 IF n MOD 2 > 0 THEN 110
70 LET n = INT(n / 2)
80 LET @(c) = 2
90 LET c = c + 1
100 IF n MOD 2 = 0 THEN 70
110 FOR i = 3 TO SQR(n) STEP 2
120 IF n MOD i > 0 THEN 170
130 LET n = INT(n / i)
140 LET @(c) = i
150 LET c = c + 1
160 IF n MOD i = 0 THEN 130
170 NEXT i
180 IF n <= 2 THEN 210
190 LET @(c) = n
200 LET c = c + 1
210 FOR y = 0 TO c
220 IF @(y) = 0 THEN 250
230 PRINT @(y); " ";
240 LET @(y) = 0
250 NEXT y
260 PRINT
270 NEXT x
Program encoded url: https://www.lucidapogee.com/netbasic/?listing=1%20REM%20https%3A%2F%2Frosettacode.org%2Fwiki%2FPrime_decomposition%0D%0A10%20LET%20loops%20%3D%20100%0D%0A20%20FOR%20x%20%3D%201%20TO%20loops%0D%0A30%20LET%20n%20%3D%20x%0D%0A40%20PRINT%20n%3B%20%22%20%3A%20%22%3B%0D%0A50%20LET%20c%20%3D%200%0D%0A60%20IF%20n%20MOD%202%20%3E%200%20THEN%20110%0D%0A70%20LET%20n%20%3D%20INT%28n%20%2F%202%29%0D%0A80%20LET%20%40%28c%29%20%3D%202%0D%0A90%20LET%20c%20%3D%20c%20%2B%201%0D%0A100%20IF%20n%20MOD%202%20%3D%200%20THEN%2070%0D%0A110%20FOR%20i%20%3D%203%20TO%20SQR%28n%29%20STEP%202%0D%0A120%20IF%20n%20MOD%20i%20%3E%200%20THEN%20170%0D%0A130%20LET%20n%20%3D%20INT%28n%20%2F%20i%29%0D%0A140%20LET%20%40%28c%29%20%3D%20i%0D%0A150%20LET%20c%20%3D%20c%20%2B%201%0D%0A160%20IF%20n%20MOD%20i%20%3D%200%20THEN%20130%0D%0A170%20NEXT%20i%0D%0A180%20IF%20n%20%3C%3D%202%20THEN%20210%0D%0A190%20LET%20%40%28c%29%20%3D%20n%0D%0A200%20LET%20c%20%3D%20c%20%2B%201%0D%0A210%20FOR%20y%20%3D%200%20TO%20c%0D%0A220%20IF%20%40%28y%29%20%3D%200%20THEN%20250%0D%0A230%20PRINT%20%40%28y%29%3B%20%22%20%22%3B%0D%0A240%20LET%20%40%28y%29%20%3D%200%0D%0A250%20NEXT%20y%0D%0A260%20PRINT%0D%0A270%20NEXT%20x

Code: [Select]
1 REM Prime Table
10 PRINT "Generating table of primes below..."
20 HTML
30 PRINT "<center><table><tr>"
40 FOR y = 1 TO 50
50 FOR x = 1 TO 20
60 LET i = i + 1
70 PRINT "<td style = 'border:1px solid black; background-color:yellow;'>"
80 PRINT i; ":<br /> "; PRIME(i)
90 PRINT "</td>"
100 NEXT x
110 PRINT "</tr><tr>"
120 NEXT y
130 PRINT "</tr></table></center>"
Program encoded url: https://www.lucidapogee.com/netbasic/?listing=1%20REM%20Prime%20Table%0D%0A10%20PRINT%20%22Generating%20table%20of%20primes%20below...%22%0D%0A20%20HTML%0D%0A30%20PRINT%20%22%3Ccenter%3E%3Ctable%3E%3Ctr%3E%22%0D%0A40%20FOR%20y%20%3D%201%20TO%2050%0D%0A50%20FOR%20x%20%3D%201%20TO%2020%0D%0A60%20LET%20i%20%3D%20i%20%2B%201%0D%0A70%20PRINT%20%22%3Ctd%20style%20%3D%20%27border%3A1px%20solid%20black%3B%20background-color%3Ayellow%3B%27%3E%22%0D%0A80%20PRINT%20i%3B%20%22%3A%3Cbr%20%2F%3E%20%22%3B%20PRIME%28i%29%0D%0A90%20PRINT%20%22%3C%2Ftd%3E%22%0D%0A100%20NEXT%20x%0D%0A110%20PRINT%20%22%3C%2Ftr%3E%3Ctr%3E%22%0D%0A120%20NEXT%20y%0D%0A130%20PRINT%20%22%3C%2Ftr%3E%3C%2Ftable%3E%3C%2Fcenter%3E%22

Take this simple program and encode it to a url using the IDE on the Net Basic page.
Code: [Select]
1 REM USD currency conversion
10 GET u
20 PRINT "$"; u; " USD ="
30 GET e
40 GET g
50 GET i
60 GET j
70 PRINT u * e;  " EUR"
80 PRINT u * g; " GBP"
90 PRINT u * i; " INR"
100 PRINT u * j; " JPY"


Once you get the url, add the variables to the url in upper case. Notice the U=25.99&E=.925881&G=.7924&I=82.628&J=145.96 part.

Here's the URL ready to go: https://www.lucidapogee.com/netbasic/?U=25.99&E=.925881&G=.7924&I=82.628&J=145.96&listing=1%20REM%20USD%20currency%20conversion%0D%0A10%20GET%20u%0D%0A20%20PRINT%20%22%24%22%3B%20u%3B%20%22%20USD%20%3D%22%0D%0A30%20GET%20e%0D%0A40%20GET%20g%0D%0A50%20GET%20i%0D%0A60%20GET%20j%0D%0A70%20PRINT%20u%20*%20e%3B%20%20%22%20EUR%22%0D%0A80%20PRINT%20u%20*%20g%3B%20%22%20GBP%22%0D%0A90%20PRINT%20u%20*%20i%3B%20%22%20INR%22%0D%0A100%20PRINT%20u%20*%20j%3B%20%22%20JPY%22%0D%0A
(for some reason the link broke, so you will have to copy/paste this one for it to work)

When you click the link, you will get exchange rates. Simply modify the GET variables to change the program output.


Try saving this form as a .html file and open it with your browser.
You will have a currency conversion app on your screen.
Code: [Select]
<form action = "https://www.lucidapogee.com/netbasic/" target = "output" method = "get">
<p>
U<br /><input type = "text" name = "U" value = "1"><br />
E<br /><input type = "text" name = "E" value = ".925881"><br />
G<br /><input type = "text" name = "G" value = ".7924"><br />
I<br /><input type = "text" name = "I" value = "82.628"><br />
J<br /><input type = "text" name = "J" value = "145.96">
</p>
<input type = "hidden" name = "listing" value = "1%20REM%20USD%20currency%20conversion%0D%0A10%20GET%20u%0D%0A20%20PRINT%20%22%24%22%3B%20u%3B%20%22%20USD%20%3D%22%0D%0A30%20GET%20e%0D%0A40%20GET%20g%0D%0A50%20GET%20i%0D%0A60%20GET%20j%0D%0A70%20PRINT%20u%20*%20e%3B%20%20%22%20EUR%22%0D%0A80%20PRINT%20u%20*%20g%3B%20%22%20GBP%22%0D%0A90%20PRINT%20u%20*%20i%3B%20%22%20INR%22%0D%0A100%20PRINT%20u%20*%20j%3B%20%22%20JPY%22%0D%0A">
<input type = "submit">
</form>
<iframe name = "output"></iframe>
97
Scripting Languages / bAsIc
« Last post by John on October 05, 2023, 08:48:45 AM »
I have removed the FANN thread due to lack of interest by the forum members, I see no reason to flood the forum with posts on a topic of little interest. I may restart the the thread on the the ScriptBasic forum once I have more time.

98
VB (5/6/CE) Classic / Re: twinBASIC
« Last post by John on August 27, 2023, 10:43:06 PM »
I'm hoping I can create 32 bit form / class DLLs I can use with ScriptBasic's COM extension.
99
VB (5/6/CE) Classic / twinBASIC
« Last post by John on August 27, 2023, 07:25:24 PM »
twinBASIC: a modern, BASIC programming language, aiming for 100% backwards compatibility with existing VB6/VBA projects.  A complete replacement development environment offering significant new features and improvements over the VB6 IDE.

VBCCR is compatible with twinBASIC in 64 bit mode.

https://twinbasic.com/
100
Code Repository / Re: 2048 Challenge
« Last post by jalih on August 13, 2023, 01:39:10 AM »
I modified my 2048 game to support mobile platforms, so it now should also work with Android and iOS platforms.

Code: [Select]
\
\ 2048 game for the 8th programming language
\
needs[ nk/gui nk/buttons nk/keyboard stack/rstack ]

: init-window-size
  mobile? if
    hw:displaysize?
  else
    400 460
  then ;

init-window-size constant HEIGHT constant WIDTH

: setup-fonts
  HEIGHT 0.05 n:* dup>r dup font:system "font1" 3 a:close ["size","font","name"] swap m:zip font:new drop
  r> 1.6 n:* dup>r dup font:system "font2" 3 a:close ["size","font","name"] const swap m:zip font:new drop
  r> 1.8 n:* dup font:system "font3" 3 a:close ["size","font","name"] const swap m:zip font:new drop ;

\ Game states
0 constant PLAY
1 constant WON
2 constant GAMEOVER

[ @scan:LEFT, @scan:RIGHT, @scan:UP, @scan:DOWN ] constant CURSOR-KEYS

with: nk
: key-state-changed?  \  s a -- a
  scancode?
  ( if 1 else 0 then ) a:map over get over ?:
  rot third set
  ' n:cmp a:2map ;

: cursor-key?  \ -- n | null
  null "keystates" CURSOR-KEYS key-state-changed?
  (
    swap a:pop -1 n:= if
      rot drop break
    else
      nip
    then
  ) 0 third a:len nip n:1- loop- drop ;

4 constant GRID-SIZE
GRID-SIZE n:sqr constant GRID-SIZE-SQUARED

[[204,192,179,255],[238,228,218,255],[237,224,200,255],[242,177,121,255],
 [245,149,99,255],[246,124,95,255],[246,94,59,255],[237,207,114,255],
 [237,204,97,255],[237,200,80,255],[237,197,63,255],[237,194,46,255]] constant bg-colors

[[249,246,242,255],[119,110,101,255]] constant fg-colors

var empty-cells
nullvar tile-items
nullvar block-list

: update-empty-cells
  a:new
  ( tile-items @ over a:_@ null? if
      drop a:push
    else
      2drop
    then
  ) 0 GRID-SIZE-SQUARED n:1- loop
  empty-cells ! ;

: random-tile
  [1,1,1,1,1,1,1,1,1,2] a:len rand-pcg swap n:mod a:_@ ;

: create-new-tile
  empty-cells @
  a:len rand-pcg swap n:mod dup>r a:@ tile-items @ swap random-tile a:! drop r> a:- drop ;

: get-row-at  \ n -- a
  a:new
  ( >r tile-items @
    third GRID-SIZE n:* r@ n:+ a:_@ null? if
      drop 0 a:push
    else
      a:push
    then rdrop
  ) 0 GRID-SIZE n:1- loop nip ;

: get-column-at  \ n -- a
  a:new
  ( >r tile-items @
    r@ GRID-SIZE n:* fourth n:+ a:_@ null? if
      drop 0 a:push
    else
      a:push
    then rdrop
  ) 0 GRID-SIZE n:1- loop nip ;

: merge  \ source-row -- indices merged-row
  a:new  \ source-row non-empty-tiles
  a:new  \ source-row non-empty-tiles indices

  ( dup>r third a:len nip a:!
    third r@ a:_@ dup 0 n:> if
      third swap a:push drop
    else
      drop
    then
    rdrop
  ) 0 4 pick a:len nip n:1- loop
 
  a:new
  \ source-row non-empty-tiles indices merged-row

  ( dup>r fourth a:len nip n:1- n:= if
      third r@ a:_@ a:push
    else
      third r@ dup n:1+ 2 a:close a:_@ a:open n:= if
        ( >r over r@ a:_@ over a:len nip n:> if
            over r@ a:@ n:1- r@ swap a:! drop
          then
          rdrop
        ) 0 5 pick a:len nip n:1- loop
        third r@ a:_@ n:1+ a:push
        2 step
      else
        third r@ a:_@ a:push
      then
    then
    rdrop
  ) 0 4 pick a:len nip n:1- loop

  ( 0 a:! ) over a:len nip 5 pick a:len nip n:1- loop 2swap 2drop ;

\ block format: [index,value,target,merged,LERP]
: build-block-list
  a:new
  tile-items @
  ( null? !if
      2dup 0 5 a:close a:push
    else
      2drop
    then
  ) a:each drop
  block-list ! ;

"moved?" constant MOVED?
"blocks" constant BLOCKS
"merged-row" constant MERGED-ROW
"source-row" constant SOURCE-ROW
"indices" constant INDICES

: pre-move
  false MOVED? w:!
  a:new BLOCKS w:! ;

: post-move
  MOVED? w:@ if
    update-empty-cells create-new-tile
  then
  BLOCKS w:@ block-list ! ;

: row-col-source-merged? \ n rev? row? -- T \\ n
  rot dup>r swap if get-row-at else get-column-at then
  swap  if
    a:rev
  then
  dup SOURCE-ROW w:!
  merge MERGED-ROW w:! INDICES w:!
  SOURCE-ROW w:@ MERGED-ROW w:@
  ' n:= a:= 2nip ;
 
locals:
: move-left
  pre-move
  ( false true row-col-source-merged? !if
      true MOVED? w:!
      ( >r SOURCE-ROW w:@ r@ a:_@ 0 n:> INDICES w:@ r@ a:_@ r@ n:= not and if
          \ checks if a merge has happened and at what position
          MERGED-ROW w:@ INDICES w:@ r@ a:_@  a:_@
          SOURCE-ROW w:@ r@ a:_@ n:>
          tile-items @ GRID-SIZE 1 rpick n:* INDICES w:@ r@ a:_@ n:+ a:_@ null? if
            drop false
          else
            drop true
          then
          and if
            \ move and merge
            BLOCKS w:@
            GRID-SIZE 1 rpick n:* r@ n:+
            tile-items @ over a:_@
            GRID-SIZE 1 rpick n:* INDICES w:@ r@ a:_@ n:+
            over n:1+
            1
            5 a:close a:push drop

            tile-items @ GRID-SIZE 1 rpick n:* r@ n:+ a:@ n:1+
            GRID-SIZE 1 rpick n:* INDICES w:@ r@ a:_@ n:+ swap a:! drop
          else
            \ move
              BLOCKS w:@
              GRID-SIZE 1 rpick n:* r@ n:+
              tile-items @ over a:_@
              GRID-SIZE 1 rpick n:* INDICES w:@ r@ a:_@ n:+
              over
              1
              5 a:close a:push drop

              tile-items @ GRID-SIZE 1 rpick n:* r@ n:+ a:@
              GRID-SIZE 1 rpick n:* INDICES w:@ r@ a:_@ n:+ swap a:! drop           
          then
          tile-items @ GRID-SIZE 1 rpick n:* r@ n:+ null a:! drop
        else
          tile-items @ GRID-SIZE 1 rpick n:* r@ n:+ a:_@ null? !if           
            drop
            BLOCKS w:@
            GRID-SIZE 1 rpick n:* r@ n:+
            tile-items @ over a:_@
            2dup
            0
            5 a:close a:push drop
          else
            drop
          then
        then
        rdrop
      ) 0 SOURCE-ROW w:@ a:len nip n:1- loop
    else
      ( >r
        tile-items @ GRID-SIZE 1 rpick n:* r@ n:+ a:_@ null? !if           
          drop
          BLOCKS w:@
          GRID-SIZE 1 rpick n:* r@ n:+
          tile-items @ over a:_@
          2dup
          0
          5 a:close a:push drop
        else
          drop
        then
        rdrop
      ) 0 SOURCE-ROW w:@ a:len nip n:1- loop
    then
    rdrop
  ) 0 GRID-SIZE n:1- loop
 
  post-move ;

locals:
: move-right
  pre-move
  ( true true row-col-source-merged? !if
      true MOVED? w:!
      SOURCE-ROW w:@ a:rev SOURCE-ROW w:!
      MERGED-ROW w:@ a:rev MERGED-ROW w:!
      INDICES w:@ a:rev INDICES w:!
     
      \ recalculate the indices from the end to the start
      ( INDICES w:@ swap GRID-SIZE n:1- third third a:_@ n:- a:! drop
      ) 0 GRID-SIZE n:1- loop

      ( SOURCE-ROW w:@ a:len nip n:1- swap n:- >r
        SOURCE-ROW w:@ r@ a:_@ 0 n:> INDICES w:@ r@ a:_@ r@ n:= not and if
        \ checks if a merge has happened and at what position
        MERGED-ROW w:@ INDICES w:@ r@ a:_@  a:_@
        SOURCE-ROW w:@ r@ a:_@ n:>
        tile-items @ GRID-SIZE 1 rpick n:* INDICES w:@ r@ a:_@ n:+ a:_@ null? if
          drop false
        else
          drop true
        then
        and if
          \ move and merge
            BLOCKS w:@
            GRID-SIZE 1 rpick n:* r@ n:+
            tile-items @ over a:_@
            GRID-SIZE 1 rpick n:* INDICES w:@ r@ a:_@ n:+
            over n:1+
            1
            5 a:close a:push drop

            tile-items @ GRID-SIZE 1 rpick n:* r@ n:+ a:@ n:1+
            GRID-SIZE 1 rpick n:* INDICES w:@ r@ a:_@ n:+ swap a:! drop
          else
            \ move
              BLOCKS w:@
              GRID-SIZE 1 rpick n:* r@ n:+
              tile-items @ over a:_@
              GRID-SIZE 1 rpick n:* INDICES w:@ r@ a:_@ n:+
              over
              1
              5 a:close a:push drop

              tile-items @ GRID-SIZE 1 rpick n:* r@ n:+ a:@
              GRID-SIZE 1 rpick n:* INDICES w:@ r@ a:_@ n:+ swap a:! drop           
          then
          tile-items @ GRID-SIZE 1 rpick n:* r@ n:+ null a:! drop
        else
          tile-items @ GRID-SIZE 1 rpick n:* r@ n:+ a:_@ null? !if           
            drop
            BLOCKS w:@
            GRID-SIZE 1 rpick n:* r@ n:+
            tile-items @ over a:_@
            2dup
            0
            5 a:close a:push drop
          else
            drop
          then
        then
        rdrop
      ) 0 SOURCE-ROW w:@ a:len nip n:1- loop
    else
      ( SOURCE-ROW w:@ a:len nip n:1- swap n:- >r
        tile-items @ GRID-SIZE 1 rpick n:* r@ n:+ a:_@ null? !if           
          drop
          BLOCKS w:@
          GRID-SIZE 1 rpick n:* r@ n:+
          tile-items @ over a:_@
          2dup
          0
          5 a:close a:push drop
        else
          drop
        then
        rdrop
      ) 0 SOURCE-ROW w:@ a:len nip n:1- loop
    then
    rdrop
  ) 0 GRID-SIZE n:1- loop
 
  post-move ;

locals:
: move-up
  pre-move
  ( false false row-col-source-merged? !if
      true MOVED? w:!
      ( >r SOURCE-ROW w:@ r@ a:_@ 0 n:> INDICES w:@ r@ a:_@ r@ n:= not and if
          \ checks if a merge has happened and at what position
          MERGED-ROW w:@ INDICES w:@ r@ a:_@  a:_@
          SOURCE-ROW w:@ r@ a:_@ n:>
          tile-items @ GRID-SIZE INDICES w:@ r@ a:_@ n:* 1 rpick n:+ a:_@ null? if
            drop false
          else
            drop true
          then
          and if
            \ move and merge
            BLOCKS w:@
            GRID-SIZE r@ n:* 1 rpick n:+
            tile-items @ over a:_@
            GRID-SIZE INDICES w:@ r@ a:_@ n:* 1 rpick n:+
            over n:1+
            1
            5 a:close a:push drop

            tile-items @ GRID-SIZE r@ n:* 1 rpick n:+ a:@ n:1+
            GRID-SIZE INDICES w:@ r@ a:_@ n:* 1 rpick n:+ swap a:! drop
          else
            \ move
              BLOCKS w:@
              GRID-SIZE r@ n:* 1 rpick n:+
              tile-items @ over a:_@
              GRID-SIZE INDICES w:@ r@ a:_@ n:* 1 rpick n:+
              over
              1
              5 a:close a:push drop

              tile-items @ GRID-SIZE r@ n:* 1 rpick n:+ a:@
              GRID-SIZE INDICES w:@ r@ a:_@ n:* 1 rpick n:+ swap a:! drop           
          then
          tile-items @ GRID-SIZE r@ n:* 1 rpick n:+ null a:! drop
        else
          tile-items @ GRID-SIZE r@ n:* 1 rpick n:+ a:_@ null? !if           
            drop
            BLOCKS w:@
            GRID-SIZE r@ n:* 1 rpick n:+
            tile-items @ over a:_@
            2dup
            0
            5 a:close a:push drop
          else
            drop
          then
        then
        rdrop
      ) 0 SOURCE-ROW w:@ a:len nip n:1- loop
    else
      ( >r
        tile-items @ GRID-SIZE r@ n:* 1 rpick n:+ a:_@ null? !if           
          drop
          BLOCKS w:@
          GRID-SIZE r@ n:* 1 rpick n:+
          tile-items @ over a:_@
          2dup
          0
          5 a:close a:push drop
        else
          drop
        then
        rdrop
      ) 0 SOURCE-ROW w:@ a:len nip n:1- loop
    then
    rdrop
  ) 0 GRID-SIZE n:1- loop
 
  post-move ;

locals:
: move-down
  pre-move
  ( true false row-col-source-merged? !if
      true MOVED? w:!
      SOURCE-ROW w:@ a:rev SOURCE-ROW w:!
      MERGED-ROW w:@ a:rev MERGED-ROW w:!
      INDICES w:@ a:rev INDICES w:!
     
      \ recalculate the indices from the end to the start
      ( INDICES w:@ swap GRID-SIZE n:1- third third a:_@ n:- a:! drop
      ) 0 GRID-SIZE n:1- loop

      ( SOURCE-ROW w:@ a:len nip n:1- swap n:- >r
        SOURCE-ROW w:@ r@ a:_@ 0 n:> INDICES w:@ r@ a:_@ r@ n:= not and if
        \ checks if a merge has happened and at what position
        MERGED-ROW w:@ INDICES w:@ r@ a:_@  a:_@
        SOURCE-ROW w:@ r@ a:_@ n:>
        tile-items @ GRID-SIZE INDICES w:@ r@ a:_@ n:* 1 rpick n:+ a:_@ null? if
          drop false
        else
          drop true
        then
        and if
            \ move and merge
            BLOCKS w:@
            GRID-SIZE r@ n:* 1 rpick n:+
            tile-items @ over a:_@
            GRID-SIZE INDICES w:@ r@ a:_@ n:* 1 rpick n:+
            over n:1+
            1
            5 a:close a:push drop

            tile-items @ GRID-SIZE r@ n:* 1 rpick n:+ a:@ n:1+
            GRID-SIZE INDICES w:@ r@ a:_@ n:* 1 rpick n:+ swap a:! drop
          else
            \ move
              BLOCKS w:@
              GRID-SIZE r@ n:* 1 rpick n:+
              tile-items @ over a:_@
              GRID-SIZE INDICES w:@ r@ a:_@ n:* 1 rpick n:+
              over
              1
              5 a:close a:push drop

              tile-items @ GRID-SIZE r@ n:* 1 rpick n:+ a:@
              GRID-SIZE INDICES w:@ r@ a:_@ n:* 1 rpick n:+ swap a:! drop           
          then
          tile-items @ GRID-SIZE r@ n:* 1 rpick n:+ null a:! drop
        else
          tile-items @ GRID-SIZE r@ n:* 1 rpick n:+ a:_@ null? !if           
            drop
            BLOCKS w:@
            GRID-SIZE r@ n:* 1 rpick n:+
            tile-items @ over a:_@
            2dup
            0
            5 a:close a:push drop
          else
            drop
          then
        then
        rdrop
      ) 0 SOURCE-ROW w:@ a:len nip n:1- loop
    else
      ( >r
        tile-items @ GRID-SIZE r@ n:* 1 rpick n:+ a:_@ null? !if           
          drop
          BLOCKS w:@
          GRID-SIZE r@ n:* 1 rpick n:+
          tile-items @ over a:_@
          2dup
          0
          5 a:close a:push drop
        else
          drop
        then
        rdrop
      ) 0 SOURCE-ROW w:@ a:len nip n:1- loop
    then
    rdrop
  ) 0 GRID-SIZE n:1- loop

  post-move ;

locals:
: test-left
  false MOVED? w:!
  ( dup>r get-row-at dup SOURCE-ROW w:!
    merge MERGED-ROW w:! INDICES w:!
    SOURCE-ROW w:@ MERGED-ROW w:@ ' n:= a:= 2nip !if
      true MOVED? w:!
      break
    then
    rdrop
  ) 0 GRID-SIZE n:1- loop
 
  MOVED? w:@ ;

locals:
: test-right
  false MOVED? w:!
  ( dup>r get-row-at a:rev dup SOURCE-ROW w:!
    merge MERGED-ROW w:! INDICES w:!
    SOURCE-ROW w:@ MERGED-ROW w:@ ' n:= a:= 2nip !if
      true MOVED? w:!
      break
    then
    rdrop
  ) 0 GRID-SIZE n:1- loop
 
  MOVED? w:@ ;

locals:
: test-up
  false MOVED? w:!
  ( dup>r get-column-at dup SOURCE-ROW w:!
    merge MERGED-ROW w:! INDICES w:!
    SOURCE-ROW w:@ MERGED-ROW w:@ ' n:= a:= 2nip !if
      true MOVED? w:!
      break
    then
    rdrop
  ) 0 GRID-SIZE n:1- loop
 
  MOVED? w:@ ;

locals:
: test-down
  false MOVED? w:!
  ( dup>r get-column-at a:rev dup SOURCE-ROW w:!
    merge MERGED-ROW w:! INDICES w:!
    SOURCE-ROW w:@ MERGED-ROW w:@ ' n:= a:= 2nip !if
      true MOVED? w:!
      break
    then
    rdrop
  ) 0 GRID-SIZE n:1- loop
 
  MOVED? w:@ ;

: can-move?
  test-left test-right or
  test-up or test-down or ;

: won?
  0
  tile-items @
  ( null? !if
      11 n:= if
        1 n:bor
      then
    else
      drop
    then
  ) a:each! drop ;

: new-win
  {
    name: "main",
    wide: @WIDTH,
    high: @HEIGHT,
    resizable: false,
    bg: "white",
    title: "2048"
  } win ;

: setup
  a:new tile-items !
  ( update-empty-cells
      create-new-tile ) 2 times

  build-block-list ;

\ draws text centered inside rectangle
: centered-text  \ rect s font bg-color fg-color --
  5 a:close
  [1,2] a:@ a:open measure-font pt>rect >r
  0 a:@ r> center-rect 0 swap a:!
  a:open draw-text ;

: index>rect  \ n -- rect
  dup GRID-SIZE n:/ n:int swap
  GRID-SIZE n:mod
  1 tuck grid ;

: draw-blocks
  block-list @
  ( -1 a:@ >r
    2 a:@ index>rect rect>pos x>pt
    over 0 a:_@ index>rect tuck rect>pos x>pt
    ( r@ n:lerp ) a:2map rdrop
    third [1,3,4] a:_@ a:open 0 n:= if
      nip
    else
      drop
    then
    >r swap rect>size pt>rect swap rect-ofs dup 4 bg-colors r@ a:_@ fill-rect
    2 r@ n:^ >s "font2" bg-colors r@ a:_@ fg-colors r> 3 n:< >n a:_@ centered-text
    drop
  ) a:each! drop ;

: 101grid
  1 0 1 grid ;

: 111grid
  1 1 1 grid ;

: >grid
  101grid rect>local grid-push ;

: declare
  "font3" [238,228,218,128] fg-colors 1 a:_@ centered-text ;

: game-over
  0 101grid "Game Over" declare ;

: won
  0 101grid "You Won!" declare ;

: do-dir \ n --
  [ ' move-left , ' move-right , ' move-up , ' move-down ]
  case ;
 
: test-won won? if
    build-block-list
    "game-state" WON set
  else
    can-move? !if
      build-block-list
      "game-state" GAMEOVER set
    then
  then null do ;

: 2048-grid
  widget if
    1 1 layout-grid-begin
      0 101grid 4 [119,110,101,255] fill-rect
      0 101grid { rows: 4, cols: 4, rgap: 8, cgap: 8, margin: 8 } layout-grid-begin   
        ( >r
          ( 1 r@ 1 grid
            4 bg-colors 0 a:_@ fill-rect
          ) 0 3 loop rdrop
        ) 0 3 loop

        "game-state" get !if
          0  \ blocks moving? flag
          block-list @
          ( -1 a:@ dup if
              0.1 n:- 0 1 n:clamp -1 swap a:! drop
              1 n:bor
            else
              2drop
            then
          ) a:each! drop
          !if
            build-block-list
            cursor-key? null? !if
              do-dir test-won
            else
              drop
            then
          else
            null do   
          then
        then
        draw-blocks         
      layout-grid-end
      [ ' noop , ' won  , ' game-over ]
      "game-state" get case
    layout-grid-end
  else
    drop
  then ;

: top
  widget if
    1 1 layout-grid-begin
      0 101grid dup
        4 [119,110,101,255] fill-rect
      { rows: 1, cols: [0.75, -1], cgap: 8, margin: 8 } layout-grid-begin   
        0 101grid rect>local grid-push
          "Restart" ( setup "game-state" PLAY set ) button-label
        0 111grid rect>local grid-push
          "Quit" ' bye button-label
      layout-grid-end
    layout-grid-end
  else
    drop
  then ;

: maintain-aspect-ratio  \ rect -- rect
  dup 2 rect@ swap 3 rect@ rot n:min tuck 2 swap rect! 3 rot rect! center-rect ;

: main-render
  {
    bg: "gray",
    flags: [ @WINDOW_NO_SCROLLBAR ],
    game-state: @PLAY
  }
  begin
    null { rows: [ 0.12, -1], cols: 1, rgap: 4, margin: 0 } layout-grid-begin
      0 >grid top
      1 101grid maintain-aspect-ratio rect>local grid-push 2048-grid
    layout-grid-end
  end ;

(
  \ swipe event "d" is dir: 0=indeterminate, 1=left, 2=right, 3=up, 4=down
  "d" m:_@ 0;
  n:1- do-dir test-won
) w:is nk:swipe

: app:main
  setup-fonts setup
  new-win ' main-render -1 render-loop ;
Pages: 1 ... 8 9 [10]