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: 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)
arr_size = 5
for i = 0 to arr_size - 1
print stack[i]
next
Expected Output: 6 7 3 4 5
for i = 1 to 5
idx = (top - i + arr_size) mod arr_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, 'ฮ', '-'
You can redefine any of the 16 default console colors using the RGB
command:
rgb 1, 0x00A5FF ! Set color #1 to orange
color 0, 1
print "Now using custom orange text!"
This allows for personalized color schemes inside your apps or tools built with Hobby BASIC.
Working with files and snapshots:
! Load text from file into array
dim lines$[]
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
TYPE is a user-defined structure that can hold variables or strings.
! 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
FIX
replaces code before execution, letting you use alternative keywords or rename commands.
TIMES
is like a compact loop. It runs a single-line command multiple times using V3
as the counter.
wait1Sec fix wait 10
display fix print
times 100 display V3 : wait1Sec
With the above fix, you can write display
instead of print
, or even use your native language!
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
Viewing output of an external command.
exec "tasklist", list$
debug(list$)
This will show the list of running processes from the Windows tasklist
command directly inside the DEBUG window.
A full Hobby BASIC demo running inside the Windows 10 console.
! DEMO.BAS
! Hobby BASIC Interpreter
! 2D Platformer Demo in Hobby BASIC.
! This is a simple 2D platformer demo designed for the Windows console.
! It showcases basic platformer mechanics, including movement and jumping, using keyboard input.
! Use the arrow keys to play.
! Press Spacebar to jump.
FILE_OR_FOLDER_EXISTS = 3
MB_ICONERROR = 0x10
! Check if system is compatible (Windows 7 or later)
if VAL(PATH(6)) < 6
alert MB_ICONERROR, PATH(3), "2D Platformer Demo requires Windows 7 or later" : end
endif
! Check the path to the tileset graphics
path_gfx$ = PATH("DATA\SNAP\TILESET.HB")
if FILE(path_gfx$, FILE_OR_FOLDER_EXISTS) = 0 then alert MB_ICONERROR, "Not found", path_gfx$ : end
SND1=700
sound PATH("DATA\MEDIA\SFX\WAV\SFX1.WAV"), SND1
! Define key constants for arrow keys and other controls
enum VK_LEFT=37, VK_UP, VK_RIGHT, VK_DOWN
FRAME1 = 7 ! Hero facing right
FRAME2 = 17 ! Hero facing left
FRAME3 = 8 ! Climbing frame
VK_ESC = 27
VK_SPACE = 32
! Set fixed tile size and initial level
TILE_SIZE = 8
level = 1
! Define an array of RGB color codes
dim rgb_color[] = \
0x000000, 0x584751, 0x49AB52, 0x3A4994, 0x3E628E, 0x43266B, 0x3381C1, 0xB8A7B0, \
0xA48E9A, 0xDE8833, 0x52B55A, 0x33A8F3, 0x304C6E, 0xACA2FF, 0x4892CE, 0xC9BBC2
! Map definitions for different levels (using arrays)
dim map1[11, 7] = \
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, \
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, \
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, \
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, \
1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 9, \
0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, \
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
dim map2[11, 7] = \
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, \
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, \
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 9, \
2, 2, 2, 2, 2, 2, 2, 5, 1, 1, 1, \
2, 2, 2, 2, 2, 2, 2, 4, 0, 0, 0, \
1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, \
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
dim map3[11, 7] = \
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, \
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, \
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, \
1, 1, 1, 1, 5, 2, 2, 2, 2, 2, 2, \
0, 0, 0, 0, 4, 2, 2, 6, 2, 2, 9, \
0, 0, 0, 0, 4, 2, 1, 1, 1, 1, 1, \
0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0
dim map4[11, 7] = \
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, \
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, \
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, \
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 9, \
1, 1, 1, 1, 5, 2, 2, 3, 2, 2, 1, \
0, 0, 0, 0, 4, 2, 2, 2, 2, 2, 0, \
0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0
! Hero's initial position for each level
dim hero_pos$[] = "00", "03", "04", "02", "03"
! Set window title
title "๐ฎ 2D Platformer Demo (Hobby BASIC) | Use โ โ โ to move, Space to jump"
! Initial setup for the screen and graphics
view 0, 7 ! hide window, font size 8x8
screen 80, 75, 0
cursor 0
color 0, 0
cls
! Load the graphics for tiles
snap 0, 0, path_gfx$
! Create the tileset (different tiles for ground, walls, hero, etc.)
bsave 00, 0, TILE_SIZE , TILE_SIZE , 0 ! ground
bsave 08, 0, TILE_SIZE , TILE_SIZE , 1 ! floor
bsave 16, 0, TILE_SIZE , TILE_SIZE , 2 ! sky
bsave 24, 0, TILE_SIZE , TILE_SIZE , 3 ! wall
bsave 32, 0, TILE_SIZE , TILE_SIZE , 4 ! ladder
bsave 40, 0, TILE_SIZE , TILE_SIZE , 5 ! ladder and floor
bsave 48, 0, TILE_SIZE , TILE_SIZE , 6 ! stone
bsave 56, 0, TILE_SIZE , TILE_SIZE , 7 ! hero right
flip 56, 0, TILE_SIZE , TILE_SIZE , 0
bsave 56, 0, TILE_SIZE , TILE_SIZE , 17 ! hero left
bsave 64, 0, TILE_SIZE , TILE_SIZE , 8 ! hero climb
bsave 72, 0, TILE_SIZE , TILE_SIZE , 9 ! sign
! Set the color scheme for the game
for index = 0 to 15
rgb index, rgb_color[index]
next
start#
view 0 ! hide window
if level = 5 then level = 1 ! Loop back to level 1
map//level[].SIZE
map_width = V1
map_height = V2
dim map[map_width, map_height]
map[].COPY map//level[]
ROWS = map_width * TILE_SIZE
COLS = map_height * TILE_SIZE
dim stage[ROWS, COLS]
screen ROWS, COLS, 0
color 9, 9
paint TILE_SIZE, TILE_SIZE, ROWS, COLS, -1, -1
draw_map() ! Draw the current map
grab 0, 0, ROWS, COLS, stage[], 0
x = VAL(LEFT(hero_pos$[level], 1)) * TILE_SIZE
y = VAL(RIGHT(hero_pos$[level], 1)) * TILE_SIZE
bloads x, y, FRAME1
view 1 ! show window
! Main game loop
main#
! Handle jump logic
if jump = 1
if y = JUMP_HEIGHT
jump = -1
vy = 1
endif
else
if falling() ! Check if the player is falling
vy = 1
else
vy = 0
endif
endif
! Handle spacebar press for jumping
if KEY(VK_SPACE) and jump = 0
sound SND1
jump = 1
JUMP_HEIGHT = y - 12 ! Set jump height
vy = -1
endif
! Handle ladder climbing
if KEY(VK_UP)
if ladder(x, y)
do: if KEY(VK_UP)
grab x, y, TILE_SIZE, TILE_SIZE, stage[], x, y
y--
bloads x, y, FRAME3 ! Climbing frame
wait 20
elseif KEY(VK_DOWN)
break
endif
until not ladder(x, y + TILE_SIZE - 1)
endif
endif
! Handle left/right movement
if KEY(VK_LEFT) and can_move(-1) and x > 0
dir = 1
vx = -1
elseif KEY(VK_RIGHT) and can_move(TILE_SIZE)
if x > ROWS - 10
level++
goto start
endif
dir = 0
vx = 1
else
vx = 0
endif
! Update position and redraw the hero
if vx or vy or jump > 0
grab x, y, TILE_SIZE, TILE_SIZE, stage[], x, y
x += vx
y += vy
if dir
bloads x, y, FRAME2 ! Hero facing left
else
bloads x, y, FRAME1 ! Hero facing right
endif
endif
wait 20
! Exit if ESC key is pressed
if not KEY(27) then goto main
color 0, 7 : cls
view 11, 1 ! Default mode
end
! Check if the player is on a ladder
sub ladder(x, y)
local i
for i = 1 to TILE_SIZE -1
cinfo x + i, y - 1
if V1 = 4 then rets 1
next
rets 0
ends
! Check if the player is falling
sub falling()
local i
for i = 1 to TILE_SIZE -1
cinfo x + i, y + TILE_SIZE
if MATCH(V1, 1, 7, 8, 10, 12, 15) then jump = 0 : rets 0
next
rets 1
ends
! Check if the player can move left or right
sub can_move(dx)
local i
for i = 0 to TILE_SIZE -1
cinfo x + dx, y + i
if MATCH(V1, 1, 7, 8, 10, 12, 15) then rets 0
next
rets 1
ends
! Draw the current level map using tiles
sub draw_map()
local x, y
for y = 0 to map_height - 1
for x = 0 to map_width - 1
bloads x * TILE_SIZE, y * TILE_SIZE, map[x, y]
next
next
ends
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.