Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Tiny Basic interpreter, with (just) enough features to play Star Trek
#11
(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 Smile

Edit ... or maybe not posdible, haha!

Yeah, probably not.
Without string variables, lots of things are not possible.

Tiny means really tiny Smile


Here we go, in 130 lines of code Big Grin

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 Smile
Reply
#12
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
Reply
#13
(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 Smile

Edit ... or maybe not possible, haha!

Here we go, in 130 lines of code Big Grin

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 Smile

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 Smile
Reply
#14
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
.pdf   KR_COMAL80_Kernel_Syntax_and_Semantics_Apr_1985.pdf (Size: 285.35 KB / Downloads: 2)
Reply
#15
(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 Smile

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 Smile
Reply
#16
(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!
Reply
#17
(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.
Reply
#18
(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!
Reply
#19
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
.zip   weird.zip (Size: 848.78 KB / Downloads: 3)
Reply


Forum Jump:


Users browsing this thread: 1 Guest(s)