• 0 Vote(s) - 0 Average
• 1
• 2
• 3
• 4
• 5
 Tiny Basic interpreter, with (just) enough features to play Star Trek Marcus Administrator       Posts: 606 Threads: 78 Joined: Jan 2018 Reputation: 16 10-30-2022, 10:52 AM (This post was last modified: 10-30-2022, 12:15 PM by Marcus.) (10-25-2022, 04:35 PM)eddavis Wrote: (10-25-2022, 04:27 PM)Marcus Wrote: I'll see if I can implement Minesweeper in Tiny Basic. I haven't thought it through, but I think it should be possible Edit ... or maybe not posdible, haha! Yeah, probably not. Without string variables, lots of things are not possible. Tiny means really tiny Here we go, in 130 lines of code Code:```1 ' PROGRAM: Minesweeper for Tiny Basic, by Marcus 2 ' =========================================================================== 3 m = 15 ' Number of mines (difficulty). 4 for i = 0 to 99 : @(i) = 10 : @(100 + i) = 0 : next i ' Clear map. 5 gosub 110: print "Dig at" : gosub 30 ' Display map, input initial dig. 6 gosub 80 ' Generate map with m mines, make pos x, y safe. 7 s = 0 : f = m ' Set game state s to 0 and unused flags f to number of mines. 8 gosub 140 ' Dig at x, y. 10 ' Game loop ================================================================= 11 gosub 110 ' Display map. 12 print "Flags left: "; : print f 13 input "Action (d = dig, f = add/remove flag, q = quit, c = cheat): ", a 14 if a = asc("d") then gosub 40 15 if a = asc("f") then gosub 50 16 if a = asc("c") then gosub 70 17 if a = asc("q") then s = -1 18 if s = 0 then goto 10 ' Loop. 20 gosub 100 21 if s < 0 then print "Bye bye!" 22 if s = 1 then print "ALL MINES MARKED, YOU SUCCEEDED!" 23 if s = 2 then print "BOOM, YOU FAILED!" 24 print 25 end 30 ' SUB: Input valid coordinates to x, y ===================================== 31 input "  X (0-9): ", x : if x < 0 or x > 9 then goto 31 32 input "  Y (0-9): ", y : if y < 0 or y > 9 then goto 32 33 return 40 ' SUB: Dig action ========================================================== 41 print "Dig at" : gosub 30 : gosub 180 ' Get coords and convert to index p. 42 if @(100 + p) then print : print : print "You can't dig there!" : return 43 if @(p) = 11 then s = 2 : return 44 gosub 140 : return 50 ' SUB: Add remove flag action ============================================== 51 print "Add or remove flag at" : gosub 30 : gosub 180 52 if @(100 + p) = 3 then @(100 + p) = 0 : f = f + 1 : return 53 if f = 0 then print : print "You're out of flags!" : return 54 if @(100 + p) > 0 then print : print "You can't place a flag there!" : return 55 f = f - 1 : @(100 + p) = 3 56 ' Change game state to completed but restore if any mine is not flagged. 57 s = 1 : for y = 0 to 9: for x = 0 to 9 58  if @(y*10 + x) = 11 and not @(100 + y*10 + x) = 3 then s = 0 59 next x : next y 60 return 70 ' SUB: Cheat action ======================================================== 71 gosub 100 : return 80 ' SUB: Init map with m mines, make position x, y "a zero" ================== 81 a = x : b  = y : c = 0 82 for y = 0 to 9 : for x = 0 to 9 83  if x < a - 1 or x > a + 1 or y < b - 1 or y > b + 1 then @(100 + c) = y*10 + x : c = c + 1 84 next x : next y 85 for i = 1 to m 86  j = rnd(c) : p = @(100 + j) : gosub 190 : @(y*10 + x) = 11 : c = c - 1 87  for k = j to c - 1 : @(100 + k) = @(100 + k + 1) : next k 88 next i 89 for i = 100 to 199 : @(i) = 0 : next i 90 x = a : y = b : return 100 ' SUB: Display actual map ================================================== 101 print : print "  0 1 2 3 4 5 6 7 8 9" : print 102 for y = 0 to 9 : print y, "  "; : for x = 0 to 9 103  if @(y*10 + x) = 11 then print "* "; : goto 105 ' Mine 104  print "  "; ' Nothing. 105 next x : print : next y : print 106 return 110 ' SUB: Display user view ================================================== 111 print : print "  0 1 2 3 4 5 6 7 8 9" : print 112 for y = 0 to 9 : print y, "  "; : for x = 0 to 9 113  p = y*10 + x : gosub 130 114 next x : print : next y : print 115 return 130 ' SUB: Print map character for position p ================================== 131 if @(100 + p) = 3 then print "F "; : return ' Flag. 132 if @(p) > 9 then print "? "; : return      ' Unexplored. 133 if @(p) = 0 then print "  "; : return      ' Empty. 134 print @(p), " "; : return                  ' Close to a mine. 140 ' SUB: Update visibility at x, y =========================================== 141 gosub 180 : if p < 0 then return 142 if @(100 + p) > 0 then return 143 @(100 + p) = 1 144 d = 1 : for i = 0 to 99 145  if @(100 + i) = 1 then d = 0 : p = i : gosub 150 146 next i 147 if d = 0 goto 144 148 return 150 ' SUB: Reveal position p and possibly mark more positions to be checked ==== 151 @(100 + p) = 2 : z = p 152 gosub 200 153 @(z) = r 154 if r > 0 then return 155 p = z : gosub 190 : x = x - 1 : y = y - 1 : gosub 180 156 if p >= 0 and @(100 + p) = 0 then @(100 + p) = 1 157 p = z : gosub 190 : y = y - 1 : gosub 180 158 if p >= 0 and @(100 + p) = 0 then @(100 + p) = 1 159 p = z : gosub 190 : x = x + 1 : y = y - 1 : gosub 180 160 if p >= 0 and @(100 + p) = 0 then @(100 + p) = 1 161 p = z : gosub 190 : x = x + 1 : gosub 180 162 if p >= 0 and @(100 + p) = 0 then @(100 + p) = 1 163 p = z : gosub 190 : x = x + 1 : y = y + 1 : gosub 180 164 if p >= 0 and @(100 + p) = 0 then @(100 + p) = 1 165 p = z : gosub 190 : y = y + 1 : gosub 180 166 if p >= 0 and @(100 + p) = 0 then @(100 + p) = 1 167 p = z : gosub 190 : x = x - 1 : y = y + 1 : gosub 180 168 if p >= 0 and @(100 + p) = 0 then @(100 + p) = 1 169 p = z : gosub 190 : x = x - 1 : gosub 180 170 if p >= 0 and @(100 + p) = 0 then @(100 + p) = 1 171 return 180 ' SUB: Convert coordinates x, y to position p, -1 if invalid =============== 181 if x < 0 or x > 9 or y < 0 or y > 9 then p = -1 : return 182 p = y*10 + x 183 return 190 ' SUB: Convert position p to coordinates x, y, no error checking =========== 191 x = p mod 10 : y = p/10 : return 200 ' SUB: Calculate number of mines nearby p ================================== 201 r = 0 202 q = p : gosub 190 : x = x - 1 : y = y - 1 : gosub 180 203 if p >= 0 then r = r + (@(p) = 11) 204 p = q : gosub 190 : y = y - 1 : gosub 180 205 if p >= 0 then r = r + (@(p) = 11) 206 p = q : gosub 190 : x = x + 1 : y = y - 1 : gosub 180 207 if p >= 0 then r = r + (@(p) = 11) 208 p = q : gosub 190 : x = x + 1 : gosub 180 209 if p >= 0 then r = r + (@(p) = 11) 210 p = q : gosub 190 : x = x + 1 : y = y + 1 : gosub 180 211 if p >= 0 then r = r + (@(p) = 11) 212 p = q : gosub 190 : y = y + 1 : gosub 180 213 if p >= 0 then r = r + (@(p) = 11) 214 p = q : gosub 190 : x = x - 1: y = y + 1 : gosub 180 215 if p >= 0 then r = r + (@(p) = 11) 216 p = q : gosub 190 : x = x - 1 : gosub 180 217 if p >= 0 then r = r + (@(p) = 11) 218 return``` It's not fast, but I think it works as it should. If you haven't played Minesweeper before (it used to come with Windows, I think) I suggest you have a look at wikipedia: https://en.wikipedia.org/wiki/Minesweeper_(video_game) Edit It would probably have been smart to dedicate part of @ to be a stack, so that sub-routines could push and pop the identifiers they're using. Messed things up a couple of times because of this (using identifiers that were needed "outside"). Hm, maybe if I ever try to implement another game  Marcus Administrator       Posts: 606 Threads: 78 Joined: Jan 2018 Reputation: 16 10-30-2022, 04:03 PM Found a display error and cleaned up the code a bit, now it's 105 lines and functions better. Code:```1 ' PROGRAM: Minesweeper for Tiny Basic, by Marcus 2 ' =========================================================================== 3 m = 15 ' Number of mines (difficulty). 4 for i = 0 to 99 : @(i) = 10 : @(100 + i) = 0 : next i ' Clear map. 5 gosub 110: print "Dig at" : gosub 30 ' Display map, input initial dig. 6 gosub 80 ' Generate map with m mines, make pos x, y safe. 7 s = 0 : f = m ' Set game state s to 0 and unused flags f to number of mines. 8 gosub 140 ' Dig at x, y. 10 ' Game loop ================================================================= 11 gosub 110 ' Display map. 12 print "Flags left: "; : print f 13 input "Action (d = dig, f = add/remove flag, q = quit, c = cheat): ", a 14 if a = asc("d") then gosub 40 15 if a = asc("f") then gosub 50 16 if a = asc("c") then gosub 70 17 if a = asc("q") then s = -1 18 if s = 0 then goto 10 ' Loop. 20 gosub 100 21 if s < 0 then print "Bye bye!" 22 if s = 1 then print "ALL MINES MARKED, YOU SUCCEEDED!" 23 if s = 2 then print "BOOM, YOU FAILED!" 24 print 25 end 30 ' SUB: Input valid coordinates to x, y ===================================== 31 input "  X (0-9): ", x : if x < 0 or x > 9 then goto 31 32 input "  Y (0-9): ", y : if y < 0 or y > 9 then goto 32 33 return 40 ' SUB: Dig action ========================================================== 41 print "Dig at" : gosub 30 : gosub 180 ' Get coords and convert to index p. 42 if @(100 + p) then print : print : print "You can't dig there!" : return 43 if @(p) = 11 then s = 2 : return 44 gosub 140 : return 50 ' SUB: Add remove flag action ============================================== 51 print "Add or remove flag at" : gosub 30 : gosub 180 52 if @(100 + p) = 3 then @(100 + p) = 0 : f = f + 1 : return 53 if f = 0 then print : print "You're out of flags!" : return 54 if @(100 + p) > 0 then print : print "You can't place a flag there!" : return 55 f = f - 1 : @(100 + p) = 3 56 ' Change game state to completed but restore if any mine is not flagged. 57 s = 1 : for y = 0 to 9: for x = 0 to 9 58  if @(y*10 + x) = 11 and not @(100 + y*10 + x) = 3 then s = 0 59 next x : next y 60 return 70 ' SUB: Cheat action ======================================================== 71 gosub 100 : return 80 ' SUB: Init map with m mines, make position x, y "a zero" ================== 81 a = x : b  = y : c = 0 82 for y = 0 to 9 : for x = 0 to 9 83  if x < a - 1 or x > a + 1 or y < b - 1 or y > b + 1 then @(100 + c) = y*10 + x : c = c + 1 84 next x : next y 85 for i = 1 to m 86  j = rnd(c) : p = @(100 + j) : gosub 190 : @(y*10 + x) = 11 : c = c - 1 87  for k = j to c - 1 : @(100 + k) = @(100 + k + 1) : next k 88 next i 89 for i = 100 to 199 : @(i) = 0 : next i 90 x = a : y = b : return 100 ' SUB: Display actual map ================================================== 101 print : print " | 0 1 2 3 4 5 6 7 8 9" : print "-+--------------------" 102 for y = 0 to 9 : print y, "| "; : for x = 0 to 9 103  if @(y*10 + x) = 11 then print "* "; : goto 105 ' Mine 104  print "  "; ' Nothing. 105 next x : print : next y : print 106 return 110 ' SUB: Display user view ================================================== 111 print : print " | 0 1 2 3 4 5 6 7 8 9" : print "-+--------------------" 112 for y = 0 to 9 : print y, "| "; : for x = 0 to 9 113  p = y*10 + x : gosub 130 114 next x : print : next y : print 115 return 130 ' SUB: Print map character for position p ================================== 131 if @(100 + p) = 3 then print "F "; : return ' Flag. 132 if @(p) > 9 then print "? "; : return      ' Unexplored. 133 if @(p) = 0 then print "  "; : return      ' Empty. 134 print @(p), " "; : return                  ' Close to a mine. 140 ' SUB: Update visibility at x, y =========================================== 141 gosub 180 : if p < 0 then return 142 if @(100 + p) > 0 then return 143 @(100 + p) = 1 144 d = 1 : for i = 0 to 99 145  if @(100 + i) = 1 then d = 0 : p = i : gosub 150 146 next i 147 if d = 0 goto 144 148 return 150 ' SUB: Reveal position p and possibly mark more positions to be checked ==== 151 @(100 + p) = 2 : z = p 152 gosub 200 153 @(z) = r 154 if r > 0 then return 155 p = z : gosub 190 : g = x : h = y 156 for v = h - 1 to h + 1 : for u = g - 1 to g + 1 157  x = u : y = v : gosub 180 : if p >= 0 and @(100 + p) = 0 then @(100 + p) = 1 158 next u : next v 159 return 180 ' SUB: Convert coordinates x, y to position p, -1 if invalid =============== 181 if x < 0 or x > 9 or y < 0 or y > 9 then p = -1 : return 182 p = y*10 + x 183 return 190 ' SUB: Convert position p to coordinates x, y, no error checking =========== 191 x = p mod 10 : y = p/10 : return 200 ' SUB: Calculate number of mines nearby p ================================== 201 r = 0 : q = p : gosub 190 : g = x : h = y 202 for v = h - 1 to h + 1 : for u = g - 1 to g + 1 203  x = u : y = v : gosub 180 : if p >= 0 then r = r + (@(p) = 11) 204 next u : next v 205 return``` eddavis Junior Member  Posts: 10 Threads: 2 Joined: Jul 2018 Reputation: 0 10-31-2022, 08:39 PM (This post was last modified: 10-31-2022, 10:09 PM by eddavis.) (10-30-2022, 10:52 AM)Marcus Wrote: (10-25-2022, 04:35 PM)eddavis Wrote: (10-25-2022, 04:27 PM)Marcus Wrote: I'll see if I can implement Minesweeper in Tiny Basic. I haven't thought it through, but I think it should be possible Edit ... or maybe not possible, haha! Here we go, in 130 lines of code Code:```1 ' PROGRAM: Minesweeper for Tiny Basic, by Marcus 2 ' ===========================================================================``` This is so, so cool!  How do you figure these things out?  Again, very cool! Quote:It's not fast, but I think it works as it should. If you haven't played Minesweeper before (it used to come with Windows, I think) I suggest you have a look at wikipedia: https://en.wikipedia.org/wiki/Minesweeper_(video_game) Plenty fast here! Quote:Edit It would probably have been smart to dedicate part of @ to be a stack, so that sub-routines could push and pop the identifiers they're using. Messed things up a couple of times because of this (using identifiers that were needed "outside"). Hm, maybe if I ever try to implement another game I wrote a Tiny Basic in GW-Basic - no locals there - and a stack is what I used for the expression parser.  Local variables were sorely missed! Again, neat piece of code!  I'm still trying to win  Marcus Administrator       Posts: 606 Threads: 78 Joined: Jan 2018 Reputation: 16 11-04-2022, 09:23 AM (This post was last modified: 11-04-2022, 09:26 AM by Marcus.) I found a specification for the Comal programming language from 1985. It was one of the first languages I ever used, on a computer called Compis. Inspired by your work, I'm darned tempted to try and write a Comal interpreter in n7. But, sigh, I should probably focus on n7 itself. Attached Files KR_COMAL80_Kernel_Syntax_and_Semantics_Apr_1985.pdf (Size: 285.35 KB / Downloads: 2) eddavis Junior Member  Posts: 10 Threads: 2 Joined: Jul 2018 Reputation: 0 11-04-2022, 11:20 AM (11-04-2022, 09:23 AM)Marcus Wrote: I found a specification for the Comal programming language from 1985. It was one of the first languages I ever used, on a computer called Compis. Inspired by your work, I'm darned tempted to try and write a Comal interpreter in n7. But, sigh, I should probably focus on n7 itself. That would be cool!  But yeah, n7 users might not appreciate it I remember Comal.  I never used it, but I remember reading about it.  1985 - I was using Turbo Pascal, after finally being liberated from COBOL in 1984  eddavis Junior Member  Posts: 10 Threads: 2 Joined: Jul 2018 Reputation: 0 11-04-2022, 12:43 PM (11-04-2022, 09:23 AM)Marcus Wrote: I found a specification for the Comal programming language from 1985. It was one of the first languages I ever used, on a computer called Compis. Inspired by your work, I'm darned tempted to try and write a Comal interpreter in n7. But, sigh, I should probably focus on n7 itself. Actually, you should write a subset N7 interpreter in N7, and give it a repl! Marcus Administrator       Posts: 606 Threads: 78 Joined: Jan 2018 Reputation: 16 11-08-2022, 04:01 PM (This post was last modified: 11-08-2022, 04:18 PM by Marcus.) (11-04-2022, 12:43 PM)eddavis Wrote: (11-04-2022, 09:23 AM)Marcus Wrote: I found a specification for the Comal programming language from 1985. It was one of the first languages I ever used, on a computer called Compis. Inspired by your work, I'm darned tempted to try and write a Comal interpreter in n7. But, sigh, I should probably focus on n7 itself. Actually, you should write a subset N7 interpreter in N7, and give it a repl! It would also be interesting to write a compiler for some language (subset or simplified version of n7, comal or maybe Minimal BASIC) in n7 that simply generates "assembler code" for the regular n7 compiler. That is, produce a file that contains nothing but an asm block and send it to n7.exe: Code:```asm     push "Hello there!"     sys 0 1     sys 0 0     push "What's your name? "     sys 107 1     sys 1 0     move @1 "!"     add @0 @1     move @1 "Nice to meet you, "     add @1 @0     push @1     sys 0 1     sys 0 0 endasm``` But right now I'm working on proper documentation to be put online. eddavis Junior Member  Posts: 10 Threads: 2 Joined: Jul 2018 Reputation: 0 11-08-2022, 10:06 PM (11-08-2022, 04:01 PM)Marcus Wrote: It would also be interesting to write a compiler for some language (subset or simplified version of n7, comal or maybe Minimal BASIC) in n7 that simply generates "assembler code" for the regular n7 compiler. That is, produce a file that contains nothing but an asm block and send it to n7.exe: Code:```asm     push "Hello there!"     sys 0 1     sys 0 0     push "What's your name? "     sys 107 1     sys 1 0     move @1 "!"     add @0 @1     move @1 "Nice to meet you, "     add @1 @0     push @1     sys 0 1     sys 0 0 endasm``` But right now I'm working on proper documentation to be put online. Yes, that (assembly for the N7 VM) would be cool! Marcus Administrator       Posts: 606 Threads: 78 Joined: Jan 2018 Reputation: 16 12-11-2022, 01:34 PM (This post was last modified: 12-11-2022, 06:37 PM by Marcus.) I did start writing this thing many weeks ago, a compiler written in n7 that targets n7's vm, and finally got some time to work more on it. You can use the command line to compile the test program with "weird.exe test.txt" and then execute the resuling executable test.exe. The compiler generates code and passes it on to the regular n7 compiler (must be the one included in the zip, since I've added some important arguments to it). Other than arrays (and functions), it would be fun to add user defined types (structs/records). They'd be very strict, less confusing than the underlying n7 tables. This is what the test program looks like: Code:```' All variables must be declared with a type before being used. The types are ' number, string and boolean. If no assignment is made for a variable it gets ' a default value of 0, "" or false. number a_number = 13, another_number = 5 + a_number, third_number string a_string = "hello", another_string = a_string + " " + "world!" boolean a_bool = true, another_bool = false, third_bool = 15 >= 14.5 number x, y ' Print two of the numeric variables without line break. print "a_number = ", a_number, " another_number = ", another_number; ' Print third number with a line break. print ", third_number = ", third_number ' Print one of the strings. print "another_string = ", another_string ' Print the booleans. print "a bool = ", a_bool, ", another_bool = ", another_bool; print ", third_bool = ", third_bool print ' There's goto. goto my_label print "I will never be seen :(" ' Add the label used in goto. my_label: ' And there's gosub. You can use : to fit multiple statements on one line. gosub my_sub : print ' The only loop implemented so far is for. First time I wrote one without using ' the stack (that would have made goto a bit complicated). for y = 0 to 3     for x = 0 to 3         print y*x, " ";     next x ' The identifier is optional.     print next y print ' And ther are if statements. Unlike naalaa, the expressions must now be ' boolean. if a_number > another_number then ' then is optional     print "nope" else if third_number = 0 then     if another_string = "hello world!" and third_bool then         print "yep"     end if else     print "also nope" end if end my_sub:     print "Here I am!"     gosub my_other_sub     return my_other_sub:     print "I'm here too!"     return``` Edit  You can add 'step' to a 'for' statement, forgot about that in the example, works as in regular basic. Attached Files weird.zip (Size: 848.78 KB / Downloads: 3) « Next Oldest | Next Newest »

Forum Jump:

Users browsing this thread: 1 Guest(s) 