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
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
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
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.
(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
(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!
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:
(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:
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
' 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.