CoolFace
Datasetpublic

EkBass/BazzBasic_AI_Guide

Dataset Card — BazzBasic AI Guide The BazzBasic AI Guide is not a JSON dataset. The BazzBasic AI Guide is a powerful guide "produced and approved" by Claude.ai, ChatGPT and Mistral Le Chat, specifically designed to be interpreted by modern AI. Usage Download latest BazzBasic-AI-guide from Files and versions Upload it to your AI's prompt or project file and it will instantly become a BazzBasic expert. Guide Summary This guide contains the official… See the full description on the dataset page: https://huggingface.co/datasets/EkBass/BazzBasic_AI_Guide.

sourceHugging Facemitupdated 20d agoView on Hugging Face
0likes90downloads
BazzBasic-AI-guide-04092026.md1011 linesDownload Raw Back to root
1# BazzBasic Language Reference
2**Version:** 1.4c | **Author:** Kristian Virtanen (EkBass) | **Platform:** Windows x64  
3**Homepage:** https://ekbass.github.io/BazzBasic/  
4**GitHub:** https://github.com/EkBass/BazzBasic  
5**Manual:** https://ekbass.github.io/BazzBasic/manual/#/  
6**Examples:** https://github.com/EkBass/BazzBasic/tree/main/Examples  
7**Rosetta Code:** https://rosettacode.org/wiki/Category:BazzBasic  
8**Rosetta Code solutions:** https://github.com/EkBass/BazzBasic/tree/main/Examples/rosetta-code  
9**BazzBasic-AI-Guide:** https://huggingface.co/datasets/EkBass/BazzBasic_AI_Guide  
10**BazzBasic Beginner's Guide:** https://github.com/EkBass/BazzBasic-Beginners-Guide/releases  
11**Communities:** https://ekbass.github.io/BazzBasic/communities.html
12
13---
14
15## ⚠️ Critical Rules — Read First
16
17| Rule | Detail |
18|------|--------|
19| Variables end with `$` | `name$`, `score$`, `x$` |
20| Constants end with `#` | `MAX#`, `PI#`, `TITLE#` |
21| Arrays declared with `DIM`, end with `$` | `DIM items$` |
22| First use of variable requires `LET` | `LET x$ = 0` — after that `x$ = x$ + 1` |
23| FOR and INPUT auto-declare, no LET needed | `FOR i$ = 1 TO 10` |
24| Functions defined **before** they are called | Put at top or INCLUDE |
25| Function name ends with `$`, called with `FN` | `FN MyFunc$(a$, b$)` |
26| Function return value **must** be used | `PRINT FN f$()` or `LET v$ = FN f$()` |
27| Arrays **cannot** be passed to functions directly | Pass individual elements, or serialize to JSON string — see *Passing Arrays to Functions* section |
28| Case-insensitive | `PRINT`, `print`, `Print` all work |
29| `+` operator does both add and concatenate | `"Hi" + " " + name$` — if either side is a string, the other is auto-converted: `"Score: " + 5` → `"Score: 5"`, no `STR()` needed |
30| Division always returns float | `10 / 3` → `3.333...` |
31| Division by zero returns `0` (no error) | Guard with `IF b$ = 0 THEN ...` if needed |
32| No integer-division operator | Use `INT(a / b)`, `FLOOR(a / b)`, or `CINT(a / b)` |
33| Errors halt the program | No `TRY`/`CATCH` or `ON ERROR` — line-numbered message printed |
34| No line-continuation char | Don't use `_`, `\`, or `&` — lexer continues automatically after operators or open `(` |
35
36---
37
38## 🚫 Common AI Mistakes (avoid these)
39
40These are the patterns LLMs most often produce when extrapolating from QBASIC, FreeBASIC, or VB. None of them are valid BazzBasic.
41
42```basic
43' ❌ WRONG                                ' ✓ CORRECT
44LET x = 5                                 LET x$ = 5
45LET MAX = 10                              LET MAX# = 10
46score$ = 0          ' first use           LET score$ = 0
47DEF FN doStuff(a, b)                      DEF FN DoStuff$(a$, b$)
48FN MyFunc$(5)       ' return ignored      LET v$ = FN MyFunc$(5)
49LET handle$ = LOADIMAGE("x.png")          LET HANDLE# = LOADIMAGE("x.png")
50CLS                 ' in graphics mode    LINE (0,0)-(W,H), 0, BF
51PRINT "x:", x$      ' in graphics mode    DRAWSTRING "x:" + STR(x$), 10, 10, RGB(255,255,255)
52FSTRING("Hi {{name$}}") ' Python-style    FSTRING("Hi {{-name$-}}")     ' triple-char markers
53ISSET(arr$(0))   ' expecting error        ' returns 0 silently — ISSET only sees scalars
54LET x$ = a$ + _ ' VBA continuation        LET x$ = a$ +     ' just leave the operator
55LET x$ = a$ + \ ' Python continuation     LET x$ = a$ +     ' or open a paren — see Line Continuation
56```
57
58**Two more traps that don't fit the table:**
59
60- Inside `DEF FN` you can read `#` constants from the outer scope but **not** `$` variables. Pass them as parameters.
61- Arrays cannot be passed to a function. Serialize with `ASJSON()` and rebuild inside the function with `ASARRAY()` — see *Passing Arrays to Functions* below.
62
63---
64
65## Minimal Valid Program
66
67```basic
68' Suggested style to use [subs]
69[inits]                     ' [name] is a plain jump label, not a keyword — see Control Flow
70    LET name$ = "World"
71
72[main]
73    PRINT "Hello, " + name$
74END
75
76' other subs after END'
77[sub:drawScreen]
78	' draw
79RETURN
80```
81
82Programs flow top to bottom. `[inits]` and `[main]` are organizational labels, not required syntax — the file would also run without them. `END` halts execution; place it at the end of the main flow so control doesn't fall through into subroutines or function definitions.
83
84---
85
86## When Generating BazzBasic Code
87
88(Suffix and return-value rules are already covered in Critical Rules above — not repeated here.)
89
90- Prefer `FSTRING` over long `+` concatenation chains for multi-variable strings
91- Place `DEF FN` definitions at the top of the file or via `INCLUDE`
92- Store every `LOADIMAGE` / `LOADSOUND` / `LOADSHAPE` handle as a `#` constant
93- In graphics mode, prefer `LINE (0,0)-(W,H), 0, BF` over `CLS`, and `DRAWSTRING` over `PRINT`
94- Wrap each frame's drawing in `SCREENLOCK ON` / `SCREENLOCK OFF`
95- If a feature isn't documented in this guide, say so rather than inventing one — BazzBasic does not silently inherit QBASIC, FreeBASIC, or VB conventions
96
97---
98
99
100## ABOUT
101
102BazzBasic is built around one simple idea: starting programming should feel nice, even fun — the ease and small joyful moments of the classic BASICs of decades past, with a fresh, modern feel.
103
104Over the years my own skills have grown and I've moved on to more versatile languages, but BASIC has always stayed fun for quick experiments — a simple adventure game, a lottery machine, a quiz, or just balls bouncing on the screen. BazzBasic was built with that in mind: a language that gets out of your way so curiosity can run free. And when you finish your first little game and crave something bigger, and eventually move on to another language — that's BazzBasic succeeding at exactly what it was meant to do.
105
106To arouse your curiosity.
107
108*EkBass*, author of BazzBasic
109
110---
111
112## Case sensitivity
113BazzBasic is not case-sensitive except with string contents.
114```basic
115let blaa$ = "Hello"
116PriNT BLAA$ ' output: Hello
117```
118
119---
120
121## Line Continuation
122
123BazzBasic has **no line-continuation character**. Do not generate `_` (VBA), `\` (Python), or `&` (other dialects). The lexer figures out continuation automatically using two rules.
124
125**Rule 1 — operator at end of line.** If a line ends in a token that cannot legally end an expression, the next line continues it:
126
127```basic
128LET total$ = price$ * count$ -
129             discount$
130
131IF score$ >= 0 AND
132   score$ <= 100 THEN
133    PRINT "Valid"
134END IF
135
136LET counter$ +=
137    step$
138```
139
140Tokens that trigger this: `+ - * / % = <> < <= > >= AND OR += -= *= /= ,`
141
142> `%` IS a real binary modulo operator (`a % b`, same precedence as `*`/`/`, same result as `MOD(a, b)`) and DOES trigger continuation like the other arithmetic operators above.
143> `MOD` is a separate thing — a function `MOD(a, b)` — not a binary operator, so it does NOT trigger continuation (a `)` at line end never continues).
144
145**Rule 2 — open paren.** Anything inside an unmatched `(` keeps reading until the matching `)`:
146
147```basic
148LET dist$ = DISTANCE(
149    x1$, y1$,
150    x2$, y2$
151)
152```
153
154Both rules combine:
155
156```basic
157LET total$ = (
158    base$ +
159    tax$
160)
161```
162
163**Trap for AI generators.** Do NOT emit a trailing `_`, `\`, `&`, or any other continuation marker — they are not BazzBasic syntax and will produce parse errors. Just leave the operator at the end of the line, or open a paren.
164
165---
166
167## Variables & Constants
168Variables and constants must be declared with LET before they can be used.  
169BazzBasic variables are not typed, but work the same way as in JavaScript, for example.  
170A variable needs the suffix $ which often is linked as STRING in traditional basic variants.  
171
172Variables require suffix "$". Constants require suffix "#".
173The suffix does not define data type — only "#" indicates immutability.
174```basic
175LET a$                      ' Declare variable without value
176LET b$, c$, d$				' Multiple variable declarations without value
177LET e$, f$ = "foo", g$ = 10	' Multiple variable declaration, e$ stays empty, f$ and g$ gets values
178
179LET name$ = "Alice"         ' String variable
180LET score$ = 0              ' Numeric variable
181
182LET PI# = 3.14159           ' Constant (immutable)
183LET TITLE# = "My Game"      ' String constant
184```
185
186**Compound assignment operators** (variables only — **not** allowed with `#` constants):
187
188```basic
189LET x$ = 1
190x$ += 5     ' add
191x$ -= 3     ' subtract
192x$ *= 2     ' multiply
193x$ /= 4     ' divide
194LET s$ = "Hello"
195s$ += " World"  ' string concatenation
196```
197
198**Scope:** All main-code variables share one scope (IF, FOR, and WHILE do NOT create new scope).  
199Main-code variables ($) are NOT accessible inside DEF FN  
200`DEF FN` functions are fully isolated — only global constants (`#`) accessible inside.
201
202**Comparison:** `"123" = 123` is TRUE (cross-type), but keep types consistent for speed.
203
204---
205
206### Built-in Constants
207- **Boolean:** `TRUE` (`1`), `FALSE` (`0`) — plain numbers, not a separate type. `IF x$ = 1` and `IF x$ = TRUE` are identical.
208- **Math:** `PI#`, `HPI#` (π/2 = 90°), `QPI#` (π/4 = 45°), `TAU#` (2π = 360°), `EULER#` (e) — `#` suffix required
209- **System:** `PRG_ROOT#` (program base directory path)
210- **Version:** 'BBVER#' (returns current version of BazzBasic, ie: "1.4c")
211- **Keyboard:** `KEY_ESC#`, `KEY_ENTER#`, `KEY_SPACE#`, `KEY_UP#`, `KEY_DOWN#`, `KEY_LEFT#`, `KEY_RIGHT#`, `KEY_F1#`…`KEY_F12#`, `KEY_A#`…`KEY_Z#`, `KEY_0#`…`KEY_9#`, `KEY_LSHIFT#`, `KEY_LCTRL#`, etc.
212
213---
214
215## Arrays
216BazzBasic arrays are fully dynamic and support numeric, string, or mixed indexing.  
217
218
219```basic
220DIM scores$                         ' Declare (required before use)
221DIM a$, b$, c$                      ' Multiple
222scores$(0) = 95                     ' Numeric indices are 0-based.
223scores$("name") = "Alice"           ' String keys are associative and unordered.
224matrix$(0, 1) = "A2"                ' Multi-dimensional
225
226DIM sounds$
227    sounds$("guns", "shotgun_shoot")    = "shoot_shotgun.wav"
228    sounds$("guns", "shotgun_reload")   = "reload_shotgun.wav"
229    sounds$("guns", "ak47_shoot")       = "shoot_ak47.wav"
230    sounds$("guns", "ak47_reload")      = "reload_ak47.wav"
231    sounds$("food", "ham_eat")          = "eat_ham.wav"
232
233PRINT LEN(sounds$())        ' 5 as full size of arrayas there is total of 5 values in array
234PRINT ROWCOUNT(sounds$())   ' 2, "guns" & "food"
235```
236
237| Function/Command | Description |
238|-----------------|-------------|
239| `LEN(arr$())` | Total element count (LEN counts all nested elements across all dimensions) |
240| `ROWCOUNT(arr$())` | Count of first-dimension rows — use this for FOR loops over multi-dim arrays |
241| `HASKEY(arr$(key))` | 1 if exists, 0 if not |
242| `DELKEY arr$(key)` | Remove one element |
243| `DELARRAY arr$` | Remove entire array (can re-DIM after) |
244| `JOIN dest$, src1$, src2$` | Merge two arrays; `src2$` keys overwrite `src1$`. Use empty `src1$` as `COPYARRAY`. |
245
246**JOIN** Matching keys from src2$ overwrite src1$ at the same level
247
248**Always check with `HASKEY` before reading uninitialized elements.**
249
250> `DIM arr$ = value` (single value, not `key=value` text) stores it at `arr$(0)` — NOT as a scalar. `DIM x$ = 5` does not make `x$` printable as a plain number; it makes `x$(0)` equal `5`. If a scalar is what you want, use `LET`, not `DIM`.
251
252---
253
254## Control Flow
255
256```basic
257' Block IF
258IF score$ >= 90 THEN
259    PRINT "A"
260ELSEIF score$ >= 80 THEN
261    PRINT "B"
262ELSE
263    PRINT "F"
264END IF                      ' ENDIF also works
265
266' One-line IF
267IF lives$ = 0 THEN GOTO [game_over]
268IF key$ = KEY_ESC# THEN GOTO [menu] ELSE GOTO [play]
269
270' FOR (auto-declares variable)
271FOR i$ = 1 TO 10 STEP 2 : PRINT i$ : NEXT
272FOR i$ = 10 TO 1 STEP -1 : PRINT i$ : NEXT
273
274' WHILE
275WHILE x$ < 100
276    x$ = x$ * 2
277WEND
278
279' Labels, GOTO, GOSUB
280[start]
281    GOSUB [sub:init]
282	' Avoid jumping into the middle of logical blocks (e.g. inside IF/WHILE)
283    GOTO [start]
284
285[sub:init]
286    LET x$ = 0
287RETURN
288
289' Dynamic jump (variable must contain "[label]" with brackets)
290LET target$ = "[menu]"
291GOTO target$
292
293' Other
294SLEEP 2000                  ' Pause for milliseconds
295END                         ' Terminate program
296```
297**Note:** Labels are case-insensitive and may contain almost any printable character.
298Whitespace is trimmed. Everything between "[" and "]" is treated as the label name.
299---
300
301## I/O
302
303| Command | Description |
304|---------|-------------|
305| `PRINT expr; expr` | `;` = no space, `,` = tab |
306| `PRINT "text";` | Trailing `;` suppresses newline |
307| `INPUT "prompt", var$` | Splits on whitespace/comma |
308| `INPUT "prompt", a$, b$` | Multiple values |
309| `LINE INPUT "prompt", var$` | Read entire line with spaces |
310| `CLS` | Clear screen |
311| `LOCATE row, col` | Move cursor (1-based) |
312| `CURPOS("row")` / `CURPOS("col")` | Read cursor row or col (1-based, matches LOCATE) |
313| `CURPOS()` | Read cursor as `"row,col"` string |
314| `COLOR fg, bg` | Text colors (0–15 palette) |
315| `SHELL("cmd")` | Run shell command, returns output |
316| `SHELL("cmd", ms)` | With timeout in ms (default 5000) |
317| `BEEB` | System beep (`Console.Beep()`) |
318
319' ; prints without spacing
320' , prints tab separation
321' Both can be mixed in a single PRINT statement
322' INPUT splits on whitespace and comma; quoted strings are treated as single values
323
324**Escape sequences in strings:** `\"` `\n` `\t` `\\`
325
326**SHELL + SQLite.** SQLite (the `sqlite3` CLI tool) is the recommended way to add a real database to a BazzBasic script — see the *SQLite Database* page in the manual for the full guide. Three things to remember when generating SHELL commands that wrap SQL:
327- Always append `2>&1` to the command, or SQL errors disappear silently.
328- Use `\"` (BazzBasic escape) to wrap the SQL for the OS shell: `SHELL("sqlite3 db.sqlite \"SELECT * FROM users\" 2>&1")`.
329- In paths use `/` or `\\` — never a single `\`.
330
331### Keyboard Input
332| Function | Returns | Notes |
333|----------|---------|-------|
334| `INKEY` | Key value or 0 | Non-blocking |
335| `KEYDOWN(key#)` | TRUE/FALSE | Held-key detection; KEYDOWN only works in graphics mode |
336| `WAITKEY(key#, ...)` | Key value | Blocks until key pressed; `WAITKEY()` = any key |
337
338### Mouse (graphics mode only)
339`MOUSEX`, `MOUSEY` — cursor position  
340`MOUSELEFT`, MOUSERIGHT, MOUSEMIDDLE — return 1 if pressed, 0 otherwise  
341`MOUSEHIDE` — hide the mouse cursor (graphics screen only)  
342`MOUSESHOW` — restore the mouse cursor (graphics screen only)
343
344### Console Read
345Returns numeric or character depending on type parameter  
346`GETCONSOLE(row, col, type)` — type: 0=char (ASCII), 1=fg color, 2=bg color
347
348---
349
350## User-Defined Functions
351
352```basic
353' Define BEFORE calling. Name must end with $.
354DEF FN Clamp$(val$, lo$, hi$)
355    IF val$ < lo$ THEN RETURN lo$
356    IF val$ > hi$ THEN RETURN hi$
357    RETURN val$
358END DEF
359
360PRINT FN Clamp$(5, 1, 10)          ' ✓ OK — return value used
361LET v$ = FN Clamp$(15, 0, 10)     ' ✓ OK
362FN Clamp$(5, 1, 10)                ' ✗ ERROR — return value unused
363```
364
365- Isolated scope: no access to global variables, only global constants (`#`)
366- Parameters passed **by value**
367- Labels inside functions are local — GOTO/GOSUB cannot jump outside
368- Supports recursion — uses the real call stack, so extremely deep recursion (thousands of levels) can overflow it. GOSUB/RETURN uses a separate, heap-based stack with no such limit.
369- Arrays as parameters not allowed. Use ASJSON to make array as JSON-string to pass it.
370- Use `INCLUDE` to load functions from separate files if many
371
372---
373
374## String Functions
375
376| Function | Description |
377|----------|-------------|
378| `ASC(s$)` | ASCII code of first char |
379| `CHR(n)` | Character from ASCII code |
380| `INSTR(s$, search$)` | Position (1-based), 0=not found; case-sensitive by default |
381| `INSTR(s$, search$, mode)` | mode: 0=case-insensitive, 1=case-sensitive |
382| `INSTR(start, s$, search$)` | Search from position (case-sensitive) |
383| `INVERT(s$)` | Reverse string |
384| `LCASE(s$)` / `UCASE(s$)` | Lower / upper case |
385| `LEFT(s$, n)` / `RIGHT(s$, n)` | First/last n chars |
386| `LEN(s$)` | String length |
387| `LTRIM(s$)` / `RTRIM(s$)` / `TRIM(s$)` | Strip whitespace |
388| `MID(s$, start)` | Substring from start (1-based) |
389| `MID(s$, start, len)` | Substring with length |
390| `REPEAT(s$, n)` | Repeat string n times |
391| `REPLACE(s$, a$, b$)` | Replace a$ with b$ in s$ |
392| `SPLIT(arr$, s$, sep$)` | Split into array, returns count. Expects array is declared with DIM |
393| `SRAND(n)` | Random alphanumeric string of length n |
394| `STR(n)` | Number to string |
395| `VAL(s$)` | String to number |
396| `SHA256(s$)` | SHA256 hash (64-char hex) |
397| `BASE64ENCODE(s$)` / `BASE64DECODE(s$)` | Base64 encode/decode |
398
399> `SRAND(n)` with `n < 0` throws an unhandled arithmetic error (`n = 0` is safe, returns `""`). Never pass an unvalidated or negative length.
400> ```basic
401> PRINT SRAND(-1)
402> ' Error: Arithmetic operation resulted in an overflow.
403> ```
404
405---
406
407## FSTRING — String Interpolation
408
409`FSTRING(template$)` substitutes `{{-name-}}` placeholders inside a template string with the value of variables, constants, or array elements. Preferred over long `+` concatenation chains.
410
411```basic
412LET name$ = "Krisu"
413LET LEVEL# = 5
414PRINT FSTRING("Hello {{-name$-}}, level {{-LEVEL#-}}")
415' Output: Hello Krisu, level 5
416```
417
418The triple-character markers `{{-` and `-}}` are deliberately unusual so they will not collide with normal text. There is no escape syntax — literal `{{-...-}}` in the template is always parsed as a placeholder.
419
420### Placeholder forms
421
422| Form | Resolves to |
423|------|-------------|
424| `{{-var$-}}` | Value of variable `var$` |
425| `{{-CONST#-}}` | Value of constant `CONST#` |
426| `{{-arr$(0)-}}` | Array element at numeric index `0` |
427| `{{-arr$(i$)-}}` | Array element at index taken from variable `i$` |
428| `{{-arr$(KEY#)-}}` | Array element at index taken from constant `KEY#` |
429| `{{-arr$(name)-}}` | Array element at literal string key `"name"` (no quotes inside FSTRING) |
430| `{{-arr$(0, i$)-}}` | Multidimensional element, mixed literal and variable indices |
431
432### Index resolution rule (array access)
433
434For each comma-separated index, FSTRING looks at the last character:
435
4361. Ends with `$` or `#` → variable / constant lookup. Halts if undefined.
4372. Parses as a number (`0`, `1.5`, `-3`) → numeric index. `arr$(01)` and `arr$(1.0)` both resolve to key `1`.
4383. Otherwise → literal string key. This is what lets `{{-player$(name)-}}` read what was stored with `player$("name") = ...`.
439
440### Notes
441
442- Whitespace inside placeholders is trimmed: `{{- name$ -}}` ≡ `{{-name$-}}`.
443- Numbers auto-stringify — no `STR()` needed for numeric variables, constants, or array elements.
444- FSTRING returns a value; you must use it (`LET`, `PRINT`, pass to function). Calling it as a bare statement is an error.
445- Errors halt the program with a line-numbered message: undefined variable, missing closing `-}}`, empty placeholder `{{--}}`, malformed array access, uninitialized array element.
446
447### Not supported (intentional)
448
449No arithmetic, function calls, nested lookups, or quoted string literals inside placeholders. Pre-compute into a variable and reference that:
450
451```basic
452' ❌ WRONG
453PRINT FSTRING("Total: {{-a$ + 5-}}")
454PRINT FSTRING("Name: {{-UCASE(name$)-}}")
455PRINT FSTRING("{{-arr$(arr2$(0))-}}")
456
457' ✓ RIGHT
458LET total$ = a$ + 5
459LET upper$ = UCASE(name$)
460LET k$     = arr2$(0)
461PRINT FSTRING("Total: {{-total$-}}, Name: {{-upper$-}}, Item: {{-arr$(k$)-}}")
462```
463
464### Common AI mistakes with FSTRING
465
466```basic
467' ❌ WRONG                                  ' ✓ CORRECT
468FSTRING("Hi {{name$}}")                     FSTRING("Hi {{-name$-}}")
469FSTRING("Hi {-name$-}")                     FSTRING("Hi {{-name$-}}")
470FSTRING("Hi {{-name-}}")    ' array key     FSTRING("Hi {{-name$-}}")
471FSTRING("Hi {{-name$-}}")   ' as stmt       LET s$ = FSTRING("Hi {{-name$-}}")
472```
473
474Inside a placeholder, `name` (no suffix) is treated as a literal string key for an array lookup, **not** as a reference to variable `name$`. Always include the suffix.
475
476### Full working example
477
478```basic
479DIM player$
480    player$("name")  = "Krisu"
481    player$("class") = "Bass"
482    player$("level") = 99
483
484DIM grid$
485    grid$(0, 0) = "X"
486    grid$(0, 1) = "O"
487    grid$(1, 0) = "."
488    grid$(1, 1) = "X"
489
490LET row$ = 1
491LET PI# = 3.14
492
493PRINT FSTRING("{{-player$(name)-}} the {{-player$(class)-}}, lvl {{-player$(level)-}}")
494PRINT FSTRING("Row {{-row$-}}: [{{-grid$(row$, 0)-}}{{-grid$(row$, 1)-}}]")
495PRINT FSTRING("Pi is roughly {{-PI#-}}")
496END
497```
498
499Output:
500```
501Krisu the Bass, lvl 99
502Row 1: [.X]
503Pi is roughly 3.14
504```
505
506---
507
508## Math Functions
509
510| Function | Description |
511|----------|-------------|
512| `ABS(n)` | Absolute value |
513| `ATAN(n)` | Arc tangent |
514| `ATAN2(n, n2)` | Returns the angle, in radians, between the positive x-axis and a vector to the point with the given (x, y) coordinates in the Cartesian plane |
515| `BETWEEN(n, min, max)` | TRUE if min ≤ n ≤ max |
516| `INBETWEEN(n, min, max)` | TRUE if min < n < max (strictly between, not equal) |
517| `CEIL(n)` / `FLOOR(n)` | Round up / down |
518| `CINT(n)` | Round to nearest integer |
519| `CLAMP(n, min, max)` | Constrain n to [min, max] |
520| `COS(n)` / `SIN(n)` / `TAN(n)` | Trig (radians) |
521| `DEG(rad)` / `RAD(deg)` | Radians ↔ degrees |
522| `DISTANCE(x1,y1, x2,y2)` | 2D Euclidean distance |
523| `DISTANCE(x1,y1,z1, x2,y2,z2)` | 3D Euclidean distance |
524| `EXP(n)` | e^n |
525| `INT(n)` | Truncate toward zero |
526| `LERP(start, end, t)` | Linear interpolation (t: 0.0–1.0) |
527| `LOG(n)` | Natural logarithm |
528| `MAX(a, b)` / `MIN(a, b)` | Larger / smaller of two |
529| `MOD(a, b)` | Remainder |
530| `a % b` | Same as `MOD(a, b)` — binary modulo operator form |
531| `POW(base, exp)` | Power |
532| `RND(n)` | Random integer 0 to n-1 if n > 0 |
533| `RND(0)` | Float between 0.0 and 1.0 (IE: 0.5841907423666761) |
534| `ROUND(n)` | Rounds to nearest integer, half rounds away from zero (`0.5→1`, `-0.5→-1`) — NOT banker's rounding |
535| `SGN(n)` | Sign: -1, 0, or 1 |
536| `SQR(n)` | Square root |
537
538**Math constants:** `PI#`, `HPI#` (PI/2), `QPI#` (PI/4), `TAU#` (PI*2), `EULER#`
539
540---
541
542## Variable Functions
543
544| Function | Description |
545|----------|-------------|
546| `ISSET(name)` | `1` if the named variable (`$`) or constant (`#`) is declared, `0` otherwise. Argument is **not evaluated** — `ISSET(undef$)` safely returns `0`. |
547
548`ISSET` is the only language-introspection function and it has tight rules:
549
550- **Scalars only.** Variables (`$`) and constants (`#`). Arrays and array elements are stored separately — `ISSET(arr$)` and `ISSET(arr$(0))` always return `0`, never an error.
551- **Bare name only.** No expressions, no string literals, no numbers. These all error with "invalid parameter":
552  ```basic
553  ISSET(a$ + b$)   ' WRONG: expression
554  ISSET("a$")      ' WRONG: string literal
555  ISSET(42)        ' WRONG: number
556  ISSET()          ' WRONG: empty
557  ```
558- **Suffix is part of the name.** `a$` and `A#` are different names:
559  ```basic
560  LET a$ = "foo"
561  PRINT ISSET(a$)  ' 1
562  PRINT ISSET(A#)  ' 0
563  ```
564- **`LET name$` (no value) still counts as set.** `LET` always registers the variable; the value just defaults to empty string for `$` and zero for numeric. `ISSET` reports declaration, not "has a meaningful value".
565
566Typical use is guarding optional setup:
567
568```basic
569IF NOT ISSET(playerName$) THEN
570    LET playerName$ = "Anonymous"
571END IF
572```
573
574---
575
576## Graphics
577
578```basic
579SCREEN 12                           ' 640×480 VGA
580SCREEN 0, 800, 600                  ' Custom size
581SCREEN 0, 1024, 768, "My Game"      ' Custom size + title
582FULLSCREEN TRUE                     ' Borderless fullscreen (graphics only)
583FULLSCREEN FALSE                    ' Windowed
584```
585
586| Mode | Resolution |
587|------|-----------|
588| 1 | 320×200 |
589| 2 | 640×350 |
590| 7 | 320×200 |
591| 9 | 640×350 |
592| 12 | 640×480 ← recommended |
593| 13 | 320×200 |
594
595### Drawing Primitives
596```basic
597PSET (x, y), color							' Pixel
598LINE (x1,y1)-(x2,y2), color                	' Line
599LINE (x1,y1)-(x2,y2), color, B             	' Box outline
600LINE (x1,y1)-(x2,y2), color, BF            	' Box filled (FAST — use instead of CLS)
601CIRCLE (cx,cy), radius, color              	' Circle outline
602CIRCLE (cx,cy), radius, color, 1           	' Circle filled
603PAINT (x, y), fillColor, borderColor       	' Flood fill
604LET c$ = POINT(x, y)                       	' Read pixel color
605LET col$ = RGB(r, g, b)                    	' Create color (0–255 each)
606```
607
608**Color values:** Every drawing primitive (`PSET`, `LINE`, `CIRCLE`, `PAINT`, `DRAWSTRING`, `LOADSHAPE`) accepts a `color` parameter that is either a palette index 0–15 or an `RGB(r, g, b)` value — mix freely. The `COLOR` text command is the exception: it accepts palette indices 0–15 only, so `COLOR RGB(...)` does **not** work.
609
610**Palette (0–15):** 0=Black, 1=Blue, 2=Green, 3=Cyan, 4=Red, 5=Magenta, 6=Brown, 7=Lt Gray, 8=Dk Gray, 9=Lt Blue, 10=Lt Green, 11=Lt Cyan, 12=Lt Red, 13=Lt Magenta, 14=Yellow, 15=White
611
612> Do **not** hand-construct packed RGB integers (e.g. `16711680`). `RGB()` tags its return value internally so it can be told apart from a palette index; a raw integer lacks that tag and will be misread as a palette index. Always use `RGB(r, g, b)`.
613
614### Screen Control
615```basic
616SCREENLOCK ON                       ' Buffer drawing (start frame)
617SCREENLOCK OFF                      ' Present buffer (end frame)
618VSYNC(TRUE)                         ' Enable VSync (default, ~60 FPS)
619VSYNC(FALSE)                        ' Disable VSync (benchmarking)
620CLS                                 ' Clear screen
621' Use CLS only with console, in graphics screen its slow
622' With graphics screen, prefer LINE BF
623```
624
625### Shapes & Images
626```basic
627' Create shape
628' LOADSHAPE and LOADIMAGE return a stable integer handle — never reassigned.
629' SDL2 owns the resource; your code only ever holds this one reference. Use constants.
630LET RECT# = LOADSHAPE("RECTANGLE", w, h, color)  ' or "CIRCLE", "TRIANGLE"
631LET IMG_PLAYER# = LOADIMAGE("player.png")         ' PNG (alpha) or BMP
632LET IMG_REMOTE# = LOADIMAGE("https://example.com/a.png") ' Download + load
633
634' Sprite sheet — sprites indexed 0-based
635DIM sprites$
636LOADSHEET sprites$, 128, 128, "sheet.png"        ' tileW, tileH, file
637MOVESHAPE sprites$(0), x, y                      ' sprites$(0) = first sprite
638
639' Transform
640' NOTE: anchor point differs by type — LOADSHAPE primitives (RECTANGLE/CIRCLE/TRIANGLE)
641' are center-anchored; LOADIMAGE images are top-left-anchored.
642MOVESHAPE RECT#, x, y               ' Position by center point (LOADSHAPE shape)
643ROTATESHAPE RECT#, angle            ' Degrees (absolute)
644SCALESHAPE RECT#, scale             ' 1.0 = original size
645DRAWSHAPE RECT#                     ' Render to buffer
646SHOWSHAPE RECT# / HIDESHAPE RECT#   ' Toggle visibility
647REMOVESHAPE RECT#                   ' Free memory (always clean up)
648```
649
650
651---
652
653### Text Rendering (SDL2_ttf.dll required)
654#### DRAWSTRING & LOADFONT
655
656
657```basic
658' Default font: Arial, 16px
659DRAWSTRING "Hello!", 100, 200, RGB(255, 255, 255)
660
661' Load alternative font — becomes the new default
662LOADFONT "comic.ttf", 24
663DRAWSTRING "Hello!", 100, 200, RGB(255, 255, 255)
664
665' Reset to Arial, 16px
666LOADFONT
667```
668
669`DRAWSTRING x, y` positions the top-left of the text. Requires `SDL2_ttf.dll` in the same directory as the interpreter. Prefer this over PRINT, which makes graphic screen easily blinking. Default font size is **16px** — not 20px.
670
671---
672
673## Sound
674
675```basic
676' LOADSOUND returns a stable integer handle — SDL2 manages the resource.
677' The handle never changes; store it in a constant to protect it from accidental reassignment.
678LET SND_JUMP# = LOADSOUND("jump.wav")   ' Load (WAV recommended)
679SOUNDONCE(SND_JUMP#)                    ' Play once, non-blocking
680SOUNDONCEWAIT(SND_JUMP#)               ' Play once, wait for finish
681SOUNDREPEAT(SND_JUMP#)                 ' Loop continuously
682SOUNDSTOP(SND_JUMP#)                   ' Stop specific sound
683SOUNDSTOPALL                            ' Stop all sounds
684```
685
686Load all sounds at startup. Call `SOUNDSTOPALL` before `END`.
687
688---
689
690## File I/O
691
692```basic
693LET data$ = FileRead("file.txt")        ' Read as string
694DIM cfg$ : LET cfg$ = FileRead("settings.txt")  ' Read as key=value array
695FILEWRITE "save.txt", data$             ' Create/overwrite
696FILEAPPEND "log.txt", entry$            ' Append
697LET ok$ = FILEEXISTS("file.txt")        ' 1=exists, 0=not
698FILEDELETE "temp.dat"                   ' Delete file
699```
700
701**key=value parsing:** When `FileRead` assigns to a `DIM`'d array, lines `key=value` become `arr$("key")`. Lines starting with `#` are comments. Perfect for `.env` files.
702
703```basic
704DIM env$
705LET env$ = FileRead(".env")
706LET API_KEY# = env$("OPENAI_API_KEY")
707```
708
709**Paths:** Use `/` or `\\` — never single `\` (it's an escape char). Relative paths are from `PRG_ROOT#`.
710`PRG_ROOT#` already ends with a directory separator — concatenate directly, don't add your own `/`:
711```basic
712LET path$ = PRG_ROOT# + "data.txt"
713```
714**FileWrite with array** saves in key=value format (round-trips with FileRead).
715
716---
717
718## Network
719
720```basic
721LET res$ = HTTPGET("https://api.example.com/data")
722LET res$ = HTTPPOST("https://api.example.com/submit", "{""key"":""val""}")
723
724' With headers (optional)
725DIM headers$
726headers$("Authorization") = "Bearer mytoken"
727headers$("Content-Type") = "application/json"
728LET res$ = HTTPGET("https://api.example.com/data", headers$)
729LET res$ = HTTPPOST("https://api.example.com/data", body$, headers$)
730
731' With timeout in seconds (optional, comes AFTER headers; default 30, 0 = no limit)
732LET res$ = HTTPGET("https://api.example.com/data", headers$, 60)
733LET res$ = HTTPPOST("http://localhost:11434/v1/chat/completions", body$, headers$, 120)
734```
735
736### Local HTTP server (LISTEN)
737
738BazzBasic can also receive requests as a local-only HTTP server, typically used as glue between a static HTML page and a BazzBasic script on the same machine.
739
740```basic
741STARTLISTEN 8080                       ' bind 127.0.0.1:8080, no admin needed
742STARTLISTEN 8080, 5000                 ' optional timeout in ms
743LET body$ = GETREQUEST()               ' POST/PUT/PATCH body, or GET query string ("" on timeout)
744SENDRESPONSE "{""status"":""ok""}"     ' must be called or browser hangs
745STOPLISTEN
746```
747
748Important rules:
749
750- **Always pair `GETREQUEST()` with `SENDRESPONSE`.** The browser is waiting on the response. Forgetting `SENDRESPONSE` makes the page hang.
751- **Bound to `127.0.0.1` only.** This is local glue, not a real web server. Do not generate code that tries to expose this on the LAN or internet.
752- **Body or query string, not full request.** `GETREQUEST()` returns just the POST body (or the GET query string without `?`). Headers, method, and URL path are NOT exposed in this version. If you need structured data, parse the body with `ASARRAY(body$)`.
753- **OPTIONS preflight is automatic.** Do NOT write code that handles `OPTIONS` — it is consumed silently and never reaches user code.
754- **CORS is automatic.** Every response carries `Access-Control-Allow-Origin: *`. No need to set it manually.
755- **One listener at a time.** Calling `STARTLISTEN` while one is already active is an error. Call `STOPLISTEN` first.
756- **Always 200 OK, always `text/plain`.** Custom status codes and content types are not supported in this version. To return JSON, just put JSON text in the body — browser-side `response.json()` still works.
757
758Typical receive-and-process pattern:
759
760```basic
761STARTLISTEN 8080
762PRINT "Waiting for browser..."
763
764LET json$ = GETREQUEST()
765DIM data$
766LET data$ = ASARRAY(json$)
767
768PRINT "Got name: " + data$("name")
769
770SENDRESPONSE "{""status"":""ok""}"
771STOPLISTEN
772END
773```
774
775---
776
777## Arrays & JSON
778
779Nested JSON maps to comma-separated keys: `data$("player,name")`, `data$("skills,0")`
780
781```basic
782' Array → JSON string
783LET json$ = ASJSON(arr$)
784
785' JSON string → array (returns element count)
786DIM data$
787LET count$ = ASARRAY(data$, json$)
788
789' Load/save JSON files
790LOADJSON arr$, "file.json"
791SAVEJSON arr$, "file.json"
792```
793
794---
795
796## Fast Trigonometry
797
798~20× faster than `SIN(RAD(x))`, 1-degree precision. Uses ~5.6 KB memory.
799
800```basic
801FastTrig(TRUE)                      ' Enable lookup tables (must call first)
802LET x$ = FastCos(45)               ' Degrees, auto-normalized 0–359
803LET y$ = FastSin(90)
804LET r$ = FastRad(180)              ' Deg→rad (no FastTrig needed)
805FastTrig(FALSE)                     ' Free memory
806```
807
808Use for raycasting, sprite rotation, particle systems, any high-freq trig.
809
810---
811
812## Date & Time
813
814```basic
815LET t$ = TIME()                    ' Current time, default format "HH:mm:ss" -> "15:21:22"
816LET t2$ = TIME("dd.MM.yyyy")       ' .NET DateTime format string -> "04.09.2026"
817LET t3$ = TIME("dddd")             ' -> "Friday"
818
819LET start$ = TICKS                 ' Milliseconds since program start
820' ... later in a loop ...
821LET elapsed$ = TICKS - start$      ' Delta time — use for frame-independent movement
822```
823
824`TICKS` is the standard way to do frame-independent (delta-time) movement in a game loop — prefer it over counting fixed `SLEEP` increments.
825
826```basic
827' ✅ Preferred: frame-independent movement
828LET lastTick$ = TICKS
829WHILE running$
830    LET delta$ = TICKS - lastTick$
831    lastTick$ = TICKS
832    x$ = x$ + speed$ * delta$ / 16   ' normalize to ~60 FPS baseline
833    GOSUB [sub:draw]
834WEND
835
836' ❌ Avoid: fixed SLEEP without delta — speed varies with actual frame rate
837SLEEP 16
838x$ = x$ + speed$
839```
840
841---
842
843## Command-Line Arguments
844
845```basic
846' bazzbasic.exe myprog.bas arg1 arg2
847PRINT ARGCOUNT         ' number of args (2 in this example)
848PRINT ARGS(0)          ' first arg  → "arg1"
849PRINT ARGS(1)          ' second arg → "arg2"
850```
851
852`ARGCOUNT` and `ARGS(n)` are 0-based; ARGS does not include the interpreter or script name.
853
854---
855
856## Libraries & INCLUDE
857
858```basic
859INCLUDE "helpers.bas"               ' Insert source at this point
860INCLUDE "MathLib.bb"                ' Load compiled library
861
862' Compile library (functions only — no loose code)
863' bazzbasic.exe -lib MathLib.bas  →  MathLib.bb
864' Function names auto-prefixed: MATHLIB_functionname$
865PRINT FN MATHLIB_add$(5, 3)
866```
867
868Library functions can read main-program constants (`#`). `.bb` files are version-locked.
869
870- **No extension fallback.** `INCLUDE "helpers"` does NOT try `helpers.bas` automatically — give the exact filename, extension included.
871- **Path resolution order:** relative to the *including file's own directory* first, then relative to the program's base path.
872- **Circular includes are detected** and halt with `Circular INCLUDE detected: <file>`.
873
874---
875
876## Passing Arrays to Functions
877
878Arrays cannot be passed directly to `DEF FN` functions, but a clean workaround exists using JSON serialization. Convert the array to a JSON string with `ASJSON`, pass the string as a parameter, then deserialize inside the function with `ASARRAY`. This is the accepted pattern in BazzBasic v1.2+.
879
880```basic
881DEF FN ProcessPlayer$(data$)
882    DIM arr$
883    LET count$ = ASARRAY(arr$, data$)
884    RETURN arr$("name") + " score:" + arr$("score")
885END DEF
886
887[inits]
888    DIM player$
889    player$("name") = "Alice"
890    player$("score") = 9999
891    player$("address,city") = "New York"
892
893[main]
894    LET json$ = ASJSON(player$)
895    PRINT FN ProcessPlayer$(json$)
896END
897```
898
899**Notes:**
900- The function receives a full independent copy — changes inside do not affect the original array
901- Nested keys work normally: `arr$("address,city")` etc.
902- Overhead is similar to copying an array manually; acceptable for most use cases
903
904---
905
906## Program Structure
907
908```basic
909' ---- 1. FUNCTIONS (or INCLUDE "functions.bas/bb") ----
910DEF FN Clamp$(v$, lo$, hi$)
911    IF v$ < lo$ THEN RETURN lo$
912    IF v$ > hi$ THEN RETURN hi$
913    RETURN v$
914END DEF
915
916' ---- 2. INIT (declare ALL constants & variables here, not inside loops) ----
917' Performance: variables declared outside loops avoid repeated existence checks.
918[inits]
919	LET SCREEN_W# = 640
920	LET SCREEN_H# = 480
921	LET MAX_SPEED# = 5
922
923    SCREEN 0, SCREEN_W#, SCREEN_H#, "My Game"
924
925    LET x$ = 320
926    LET y$ = 240
927    LET running$ = TRUE
928
929' ---- 3. MAIN LOOP ----
930[main]
931    WHILE running$
932        IF INKEY = KEY_ESC# THEN running$ = FALSE
933        GOSUB [sub:update]
934        GOSUB [sub:draw]
935        SLEEP 16
936    WEND
937    SOUNDSTOPALL
938END ' place at the end of main program so BazzBasic wont fall to subs in runtime
939
940' ---- 4. SUBROUTINES (or INCLUDE "subs.bas") ----
941[sub:update]
942    IF KEYDOWN(KEY_LEFT#)  THEN x$ = x$ - MAX_SPEED#
943    IF KEYDOWN(KEY_RIGHT#) THEN x$ = x$ + MAX_SPEED#
944RETURN
945
946[sub:draw]
947    SCREENLOCK ON
948    LINE (0,0)-(SCREEN_W#, SCREEN_H#), 0, BF
949    CIRCLE (x$, y$), 10, RGB(0, 255, 0), 1
950    SCREENLOCK OFF
951RETURN
952```
953
954**Key conventions:**
955- Variables: `camelCase$` | Constants: `UPPER_SNAKE_CASE#` | Functions: `PascalCase$`
956- Labels: `[gameLoop]` for jump targets, `[sub:name]` for subroutines
957- Image/sound/shape IDs are stable integer handles — **always** store as constants: `LET MY_IMG# = LOADIMAGE("x.png")` — never use `$` variables for these
958- Group many IDs → use arrays: `DIM sprites$` / `sprites$("player") = LOADIMAGE(...)` — but prefer named constants when count is small
959
960---
961
962## Performance Tips
963
964- `LINE (0,0)-(W,H), 0, BF` to clear — much faster than `CLS`
965- Always wrap draw code in `SCREENLOCK ON` / `SCREENLOCK OFF`
966- Store `RGB()` results in constants/variables — don't call RGB in hot loops
967- Declare all variables in `[inits]`, not inside loops or subroutines
968- Use `FastTrig` for any loop calling trig hundreds of times per frame
969- `SLEEP 16` in game loop → ~60 FPS
970
971---
972
973## Known Limitations
974
975Things to be aware of — most are deliberate design decisions, a few are practical constraints.
976
977- **No line numbers.** Never supported, never will be.
978- **Platform: Windows x64 only.** Linux and macOS are not supported. Browser/Android are not feasible — the runtime depends on SDL2 via P/Invoke.
979- **Arrays cannot be passed to functions.** Use the `ASJSON` / `ASARRAY` round-trip pattern. The function receives an independent copy.
980- **`DEF FN` scope is fully isolated.** Functions can read global `#` constants but cannot see any `$` variables from the outer scope. Pass values as parameters.
981- **No block scope.** `IF`, `FOR`, and `WHILE` do not create new variable scopes — all main-code variables share one namespace.
982- **No exception handling.** There is no `TRY`/`CATCH` and no `ON ERROR`. Runtime errors halt the program with a line-numbered message printed to the console.
983- **Division by zero returns `0` silently.** No exception, no warning. Guard with `IF b$ = 0 THEN ...` when correctness matters.
984- **No integer-division operator.** Use `INT(a / b)`, `FLOOR(a / b)`, or `CINT(a / b)` depending on the rounding behavior you need.
985- **Compiled `.bb` libraries are version-locked** to the BazzBasic build that produced them. Recompile after upgrading the interpreter.
986- **`DEF FN` definitions must precede their first call** in source order. Forward references don't resolve.
987
988---
989
990## IDE Features (v1.4c)
991
992### New File Template
993When the IDE opens with no file (or a new file), this template is auto-inserted:
994```basic
995' BazzBasic version {ver_num}
996' https://ekbass.github.io/BazzBasic/
997```
998
999### Beginner's Guide
1000- **IDE:** Menu → **Help** → **Beginner's Guide** — opens `https://github.com/EkBass/BazzBasic-Beginners-Guide/releases` in default browser
1001- **CLI:** `bazzbasic.exe -guide` or `bazzbasic.exe -help` — prints URL to terminal
1002
1003### Check for Updates
1004- **IDE:** Menu → **Help** → **Check for updated...** — IDE reports if a newer version is available
1005- **CLI:** `bazzbasic.exe -checkupdates`
1006
1007### Compile via IDE
1008- **Menu → Run → Compile as Exe** — compiles open file to standalone `.exe` (auto-saves first)
1009- **Menu → Run → Compile as Library (.bb)** — compiles open file as reusable `.bb` library (auto-saves first)
1010
1011EOF