The IF...THEN...ELSE structure is used to control program flow based on conditions.
IF SCORE >= 50
PRINT "You passed!"
ENDIF
IF (GRADE$ = "A" AND ATTENDANCE >= 90) OR AGE > 18
PRINT "Great job!"
ELSEIF (GRADE$ = "B" OR AGE <= 18) AND ATTENDANCE >= 50
PRINT "Good effort!"
ELSE
PRINT "Keep improving!"
ENDIF
IF AGE >= 18
IF COUNTRY$ = "USA" THEN PRINT "You can vote."
ELSE
PRINT "You are too young to vote."
ENDIF
IF BALANCE < 0 THEN PRINT "Your account is overdrawn!" ELSE PRINT "Balance OK."
IF LOGIN$ = "admin"
PRINT "Access granted."
ENDIF
The IIF function evaluates a condition and returns one of two values.
STATUS$ = IIF(SCORE >= 60, "Pass", "Fail")
DISCOUNT = IIF(QUANTITY > 10, 1, 0)
COUNTRY$ = IIF(COUNTRY$ = "", "Unknown", COUNTRY$)
The SELECT...CASE structure simplifies multiple condition checks.
INPUT "Enter day of week (1-7): ", DAY
SELECT CASE DAY
CASE IS 1 :
PRINT "Monday"
BREAK
CASE IS 2 :
PRINT "Tuesday"
BREAK
CASE IS 3 :
PRINT "Wednesday"
BREAK
CASE IS 4 :
PRINT "Thursday"
BREAK
CASE IS 5 :
PRINT "Friday"
BREAK
CASE IS 6,7 :
PRINT "Weekend"
BREAK
CASE :
PRINT "Invalid day"
ENDSEL
SELECT CASE
CASE TEMP > 30 :
PRINT "Hot"
BREAK
CASE TEMP >= 20 AND TEMP <= 30 :
PRINT "Warm"
BREAK
CASE TEMP < 20 :
PRINT "Cold"
BREAK
ENDSEL
The FOR...NEXT loop in Hobby BASIC is used to repeat a block of code for a specific number of times.
Example 1: Basic FOR Loop with PASS
FOR I = 1 TO 5
IF I = 3 THEN PASS
PRINT I
NEXT I
Expected Output: 1 2 4 5
The DO...UNTIL loop executes a block of code repeatedly until a condition is met.
Example 2: DO Loop with PASS
I = 0
DO
I = I + 1
IF I = 2 THEN PASS
PRINT I
UNTIL I = 4
Expected Output: 1 3 4
The WHILE...ENDW loop repeats a block of code as long as the condition is true.
โ๏ธ Note: Hobby BASIC uses ENDW instead of WEND.
Example 3: WHILE Loop
I = 1
WHILE I <= 5
PRINT I
I = I + 1
ENDW
Expected Output: 1 2 3 4 5
The PASS statement is used to skip the current iteration of a loop. It is similar to the continue statement in C.
Example 4: Simple PASS Usage
FOR I = 1 TO 3
PASS
PRINT I
NEXT I
Expected Output: (Nothing printed)
The BREAK statement is used to exit a loop prematurely when a certain condition is met.
Example 5: Simple BREAK Usage
FOR I = 1 TO 9
IF I = 5 THEN BREAK
PRINT I
NEXT
Expected Output: 1 2 3 4
You can also use BREAK and PASS inside nested loops to control the flow.
Example 6: Nested Loops with PASS
FOR I = 1 TO 3
FOR J = 1 TO 3
IF J = 2 THEN PASS
PRINT "I=", I, " J=", J
NEXT J
NEXT I
Expected Output:
I=1 J=1
I=1 J=3
I=2 J=1
I=2 J=3
I=3 J=1
I=3 J=3
In this example, we will search for prime numbers up to a limit using BREAK and PASS.
Example 7: Search for Prime Numbers
LIMIT = 20
PRINT "Prime numbers up to ", LIMIT
PRINT 2, " ";
FOR NUM = 3 TO LIMIT STEP 2
ISPRIME = 1
I = 3
WHILE I * I <= NUM
IF NUM % I = 0
ISPRIME = 0
BREAK
ENDIF
I = I + 2
ENDW
IF ISPRIME THEN PRINT NUM;
NEXT
Expected Output:
Prime numbers up to 20
2 3 5 7 11 13 17 19
This function searches for a target value in an array and returns its index if found.
sub searchArray(arr[], target)
arr[].FIND target
rets V0
ends
dim numbers[50].RND 50
searchValue = 10
index = searchArray(numbers[], searchValue)
if index <> 0
PRINT "Value ", searchValue, " found at position ", index - 1
else
PRINT "Value ", searchValue, " not found in the array"
endif
This function loads lines of text from a file into an array.
sub loadFileIntoArray(filePath$, lines$[])
if SIZE(filePath$) = -1 then rets -1
lines$[].FILE filePath$
rets V0
ends
dim fileBuffer$[100].ZERO
lineCount = loadFileIntoArray("Licence.txt", byref fileBuffer$[])
if lineCount = -1
PRINT "Error: File not found"
end
endif
for i = 0 to lineCount - 1
PRINT fileBuffer$[i]
next
This function swaps two values using a temporary variable.
sub swapValues(x, y)
local temp = x
x = y
y = temp
ends
firstValue = 5
secondValue = 10
swapValues(byref firstValue, byref secondValue)
PRINT "After swapping: ", firstValue, " and ", secondValue
This function checks if a string is a palindrome (reads the same forwards and backwards).
sub checkPalindrome(inputString$)
local reversedString$
local cleanedInput$
cleanedInput$ = REPLACE(inputString$, " ", "")
reversedString$ = REVERSE(cleanedInput$)
if UCASE(reversedString$) = UCASE(cleanedInput$)
rets "The string is a palindrome!"
else
rets "The string is not a palindrome!"
endif
ends
result$ = checkPalindrome("Rotator")
PRINT result$
In Hobby BASIC, the stack operates in a LIFO (Last In, First Out) manner and consists of 262,140 double words. You can manipulate it using the basic PUSH
and POP
commands or directly through the stack[]
array.
โ๏ธ Note: The stack[]
array and the internal stack are the same. Any operation on stack[]
directly affects the stack. However, commands like FILL
, SHUFFLE
, SORT
, etc., do not update the internal stack pointer, so use them with care.
push 100
push 'A'
pop x
This sends 100 and the ASCII of 'A' to the stack, and retrieves 'A' into x
.
push 1, 2, 3, 'A'
top = PEEK(10) ! Get top of the stack
print CHR(stack[top - 1]) ! Prints 'A'
pop 4 ! pop 4 times
x = 0
dim stack[10] ! reinitialize stack with 10 elements
times 10 push x++ ! pushes 0..9 onto the stack
stack[].SORTD ! now stack[] = [9, 8, โฆ, 0]
for i = 0 to 9
print stack[i]
next
Expected Output: 9 8 7 6 5 4 3 2 1 0 (Descending order)
dim stack[5]
push 10, 20, 30, 20, 40
stack[].REPLACE 20, 99
times 5 pop x : print x
Expected Output: 40 99 30 99 10
dim stack[5]
push 1, 2, 3, 4, 5
stack[].SHUFFLE
times 5 pop x : print x
โ๏ธ Note: SHUFFLE randomly shuffles stack values. The result will vary.
The Hobby BASIC stack is circular. When it becomes full, new values start replacing older ones from the beginning of the array.
dim stack[5]
push 1, 2, 3, 4, 5
push 6, 7
top = PEEK(10)
size = 5
for i = 0 to size - 1
print stack[i]
next
Expected Output: 6 7 3 4 5
for i = 1 to 5
idx = (top - i + size) mod size
print stack[idx]
next
Expected Output: 7 6 5 4 3
times 5 pop x : print x
Expected Output: 7 6 5 4 3
The stack in Hobby BASIC is a powerful tool. Its circular nature makes it highly efficient not only for simple PUSH
and POP
operations but also for advanced manipulations like sorting, shuffling, and value replacements using the stack[]
array.
This drawing tool is developed in Hobby BASIC and designed specifically for use within the Hobby BASIC environment. DRAW can load, create, edit, and save ANSI images.
Ctrl + Z
to undo the last action.F11
to export the loader script.F12
to insert text at the cursor.Q
to quit the program.Click on the BG or FG labels to select background or foreground color.
Then choose one of the 16 available colors from the color picker.
๐ก Right-click on the labels to swap the foreground and background colors.
If an area is selected, the color swap will apply to that area automatically.
โ๏ธ Note: This method overrides color number 8 (GRAY) as it is used for temporary storage.
Right-click on the color picker to open the color dialog box.
Any change you make to one of the 16 basic colors in the console will affect the entire DRAW window.
Remember, DRAW itself is a console window made with Hobby BASIC.
When you save an image in DRAW, the program automatically stores the associated color scheme in the DATA\TEMP folder. The scheme is saved as a plain text file (.TXT) with the same name as your image. To load this scheme, use Option 3 from the main menu.
For the program to function correctly, enable the Use Legacy Console option:
The DRAW program, Hobby BASIC's drawing tool, offers three options when starting:
โ ๏ธ Note: Options 1 and 2 define the font and canvas size used during your drawing session. Make sure to choose the correct mode when loading an image you previously created, to match its original dimensions.
For example, if we save an image named TEST.ANS
in the DATA\MEDIA\ANSI\
folder, we can load it as follows:
! ROWS = 80
! COLS = 25
screen 80, 50, 0
cls
ansi PATH("DATA\MEDIA\ANSI\TEST.ANS")
inkey
The critical setting here is ROWS
, which must be 80.
The following code creates a new ANSI image, TEST1.ANS
, with a size of 40x25 from the original TEST.ANS
file.
screen 80, 50, 0
cls
ansi PATH("DATA\MEDIA\ANSI\TEST.ANS")
ansi 0, 0, 40, 25, PATH("DATA\MEDIA\ANSI\TEST1.ANS")
inkey
To load TEST1.ANS
, the console window must match the image size:
screen 40, 25, 0
cls
ansi PATH("DATA\MEDIA\ANSI\TEST1.ANS")
inkey
SNAP loads a snapshot file at position x, y, or saves a rectangular area of the screen to a file. Snapshot files require the .HB extension. SNAP allows us to load an image of any size into a console window of any dimensions (as long as it fits within the window).
To load TEST.ANS
and create a snapshot named TEST.HB
with a size of 40x25, use the following code:
screen 80, 50, 0
cls
ansi PATH("DATA\MEDIA\ANSI\TEST.ANS")
snap 0, 0, 40, 25, PATH("DATA\SNAP\TEST.HB")
inkey
Now, we can load this snapshot at any position within the console window:
screen 80, 50, 0
cls
snap 10, 10, PATH("DATA\SNAP\TEST.HB")
inkey
Useful one-liners and built-in functions:
print ABS(-10) ! 10
print RND()%100 ! random number 0-99
print STR(25) + " years" ! "25 years"
print FORMAT(1, 23456) ! "22,9 KB"
print PAD("42", '0', 5) ! "00042"
print EXTRACT("abc123!@#", 0) ! "123"
๐ Use PAUSE
or INKEY
to prevent the window from closing.
String manipulation with built-ins:
a$ = "Hello World"
print LEFT(a$, 5) ! "Hello"
print RIGHT(a$, 5) ! "World"
print REVERSE(a$) ! "dlroW olleH"
a$(0) = 'h' ! Change first char (0-based)
Working with arrays and array functions:
dim nums[5] = 5, 3, 1, 4, 2
nums[].SORTA
nums[].OUT 3
nums[].REPLACE 3, 99
nums[].OUT 3
! 2D example:
dim matrix[2, 2] = 1, 2, 3, 4
print matrix[0, 0], matrix[1, 1] ! prints 1 4
Manipulate screen output using built-in commands:
cls
color 1, 14
print "Yellow on Blue!"
paint 0, 0, 80, 25, 'ฮ', 1
invert 10, 10, 15, 5
redraw 10, 10, 15, 5, 'ฮ', '-'
Working with files and snapshots:
! Load text from file
dim lines$[16]
lines$[].FILE "LICENCE.TXT"
for i = 0 to SIZE(lines$[]) - 1
print lines$[i]
next
! Save a portion of screen
snap 0, 0, 40, 15, PATH("DATA\SNAP\TEST.HB")
! Load the snapshot
snap 10, 10, PATH("DATA\SNAP\TEST.HB")
Create a simple digital clock:
while 1
print at 0, 0, LEFT(PATH(10), 8) ! system time
wait 1000
endw
! Define a Coord structure for 3 points
type Coord (x, y) 3
! Assign coordinates to each point
Coord:[0].x = 10 : Coord:[0].y = 5 ! Point 0 at (10,5)
Coord:[1].x = 20 : Coord:[1].y = 15 ! Point 1 at (20,15)
Coord:[2].x = 30 : Coord:[2].y = 25 ! Point 2 at (30,25)
! Loop through and print each point
for i = 0 to 2
print "Point ", i, ": (", Coord:[i].x, ", ", Coord:[i].y, ")"
next
Wait for a key press and display the key code:
LOOP#
inkey
! V0 = Keycode
! V1 = SHIFT, ALT, CTRL, etc.
! V2 = F1..F12, INS, DEL, HOME, Arrows Keys
print "Key:", V0, " Mod:", V1, " Extra:", V2
if V0 = 13 then print "Enter was pressed"
if V0 = 27 then end ! Exit with Esc
goto LOOP
Track mouse position and button state:
while 1
mouse
! V0 = mouse x
! V1 = mouse y
! V2 = button: 1 left, 2 right, 4 double-click
print "X:", V0, " Y:", V1, " Btn:", V2
if V2 = 2 then print "Right click!"
if V2 = 1 then break ! Left click to exit
wait 1
endw
Use the DEBUG window to visualize variable contents in real time:
dim values[5] = 10, 20, 30, 40, 50
for i = 0 to 4
DEBUG(i, values[i]) ! show key-value pairs in debugger
next
Hobby BASIC is a lightweight yet surprisingly powerful BASIC interpreter for the Windows console, written entirely in x86 assembly.
It enables the creation of games with ANSI graphics in the console, which is quite unusual.
What began in 2015 as a personal fun project continues to evolve to this day.
This quick guide offers just a small glimpse of what Hobby BASIC can do.
๐ To download it and learn more, visit the Hobby BASIC topic on the Flat Assembler forum.
This guide covers the fundamental concepts of Hobby BASIC, from conditions and loops to functions and drawing tools. With this knowledge, you can start creating your own programs.