📘 Hobby BASIC - Get Started

✅ Conditionals in Hobby BASIC

1. IF...THEN...ELSE Statement

The IF...THEN...ELSE structure is used to control program flow based on conditions.

Example 1: Simple IF Statement

IF SCORE >= 50
    PRINT "You passed!"
ENDIF

Example 2: IF...ELSEIF...ELSE

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

Example 3: Nested IF Statements

IF AGE >= 18
    IF COUNTRY$ = "USA" THEN PRINT "You can vote."
ELSE
    PRINT "You are too young to vote."
ENDIF

Example 4: Single-line IF with THEN

IF BALANCE < 0 THEN PRINT "Your account is overdrawn!" ELSE PRINT "Balance OK."

Example 5: IF without ELSE

IF LOGIN$ = "admin"
    PRINT "Access granted."
ENDIF

2. IIF Function

The IIF function evaluates a condition and returns one of two values.

Example 6: Basic IIF Usage

STATUS$ = IIF(SCORE >= 60, "Pass", "Fail")

Example 7: Numeric IIF Example

DISCOUNT = IIF(QUANTITY > 10, 1, 0)

Example 8: String Assignment with IIF

COUNTRY$ = IIF(COUNTRY$ = "", "Unknown", COUNTRY$)

3. SELECT...CASE...ENDSEL Statement

The SELECT...CASE structure simplifies multiple condition checks.

Example 9: Simple SELECT...CASE

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 IS :
    PRINT "Invalid day"
ENDSEL

Example 10: SELECT...CASE without parameter

SELECT CASE
CASE TEMP > 30 :
    PRINT "Hot"
    BREAK
CASE TEMP >= 20 AND TEMP <= 30 :
    PRINT "Warm"
    BREAK
CASE TEMP < 20 :
    PRINT "Cold"
    BREAK
ENDSEL

✅ Loops and Control Statements

1. FOR...NEXT Loop

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

2. DO...UNTIL Loop

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

3. WHILE...ENDW Loop

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

4. PASS Statement

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)

5. BREAK Statement

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

6. Nested Loops with BREAK and PASS

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

7. Complex Example: Search for Prime Numbers

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

✅ Functions in Hobby BASIC

1. Validated User Input (1–100)

This function prompts for numeric input and checks for valid range and characters.

Example: getValidatedNumber Function

sub getValidatedNumber()

    while 1
        ! prompt for input
        INPUT "Please enter a number (from 1 to 100):", num$

        ! remove whitespace
        num$ = TRIM(0, num$)

        ! check if input is empty
        if not LEN(num$)
            pass

        ! check for invalid characters (only digits allowed)
        elseif not INSET(num$, "0123456789")
            PRINT "Invalid characters in string, please try again."

        ! convert to number and check range
        else
            num = VAL(num$)
            if num < 1 or num > 100
                PRINT "Invalid value, please try again."
            else
                rets num     ! return valid number
            endif
        endif
    endw
ends

! call the function and display the result
number = getValidatedNumber()
PRINT "You entered:", number

✍️ Note: The INPUT command needs an active screen buffer to work.

view 11
screen 80, 30, 3000

2. Searching for a Value in an Array

This function searches for a target value in an array and returns its index if found.

Example: searchArray Function

sub searchArray(arr[], target)

    ! search for the target value in the array
    arr[].FIND target
    rets V0    ! return the index (0 if not found)
ends

! create an array with 50 random numbers (1–50)
dim numbers[50].RND 50

searchValue = 10

! call the function and store the result
index = searchArray(numbers[], searchValue)

! check if the value was found
if index <> 0
    PRINT "Value ", searchValue, " found at position ", index - 1
else
    PRINT "Value ", searchValue, " not found in the array"
endif

3. Loading File Content into an Array

This function loads lines of text from a file into an array.

Example: loadFileIntoArray Function

sub loadFileIntoArray(filePath$, lines$[])

    ! check if file exists (SIZE returns -1 if not found)
    if SIZE(filePath$) = -1 then rets -1

    ! load file contents into string array
    lines$[].FILE filePath$

    rets V0    ! return number of lines loaded
ends

! create a string array with 100 empty slots
dim fileBuffer$[100].ZERO

! load the file into the array and get the line count
lineCount = loadFileIntoArray("Licence.txt", byref fileBuffer$[])

! check for file not found error
if lineCount = -1
    PRINT "Error: File not found"
    end
endif

! print each line of the loaded file
for i = 0 to lineCount - 1
    PRINT fileBuffer$[i]
next

4. Swapping Two Values

This function swaps two values using a temporary variable.

Example: swapValues Function

sub swapValues(x, y)

    ! store the value of x in a temporary variable
    local temp = x

    ! swap the values
    x = y
    y = temp
ends

firstValue = 5
secondValue = 10

! swap the two values using byref parameters
swapValues(byref firstValue, byref secondValue)

! print the swapped values
PRINT "After swapping: ", firstValue, " and ", secondValue

5. Checking if a String is a Palindrome

This function checks if a string is a palindrome (reads the same forwards and backwards).

Example: checkPalindrome Function

sub checkPalindrome(inputString$)

    ! declare local variables
    local reversedString$
    local cleanedInput$

    ! remove spaces from the input
    cleanedInput$ = REPLACE(inputString$, " ", "")

    ! reverse the cleaned string
    reversedString$ = REVERSE(cleanedInput$)

    ! compare the reversed and original (case-insensitive)
    if UCASE(reversedString$) = UCASE(cleanedInput$)
        rets "The string is a palindrome!"
    else
        rets "The string is not a palindrome!"
    endif
ends

! call the function and display the result
result$ = checkPalindrome("Rotator")
PRINT result$

✅ The Stack in Hobby BASIC

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.

Example: Basic PUSH and POP

push 100
push 'A'
pop x

This sends 100 and the ASCII of 'A' to the stack, and retrieves 'A' into x.

Example: Multiple PUSH and Top Check

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

Sorting the Stack

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)

Value Replacement

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

Extra: Stack SHUFFLE

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.

Handling the Circular Stack

The Hobby BASIC stack is circular. When it becomes full, new values start replacing older ones from the beginning of the array.

Example: Circular Stack Behavior

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

Reading Top to Bottom with Wrap-around

🔄 Always use mod to handle circular wrap‑around when reading from top to bottom.
for i = 1 to 5
    idx = (top - i + arr_size) mod arr_size
    print stack[idx]
next

Expected Output: 7 6 5 4 3

Alternative: Simple POP

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.

✅ Drawing Tool Guide

Introduction

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.

Image

Basic Controls

The Attributes Picker

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.

The Color Dialog Box

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.

🎨 About Color Schemes

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.

Function Keys

📌 Windows 10 & 11 Compatibility

For the program to function correctly, enable the Use Legacy Console option:

  1. Right-click the app title bar and select Properties.
  2. Enable Use Legacy Console.
  3. Restart the console.

✅ Creating Snapshots

Introduction

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.

Loading an ANSI Image

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.

Saving a Portion of an Image

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

Loading the Cropped Image

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

ℹ️ Using SNAP for More Flexibility

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).

Creating and Loading a Snapshot

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

📘 Hobby BASIC - Try These

📌 Built-in Functions Overview

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.

🧵 Strings in Hobby BASIC

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)

🧮 Arrays (1D & 2D)

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

🎨 Console Drawing & Screen Tools

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!"

You can also use the alternate format with separate RGB components:

rgb 1, 255, 165, 0   ! equivalent to rgb 1, 0x00A5FF (note: color is in 0xBBGGRR format)

This allows for personalized color schemes inside your apps or tools built with Hobby BASIC.

📂 File & Snapshot Utilities

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")

🔁 Mini Lab: Digital Clock

Create a simple digital clock:

while 1
  print at 0, 0, LEFT(PATH(10), 8)    ! system time
  wait 1000
endw

🗺️ Mini Mini Lab: Three Points

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

⌨️ Keyboard Input

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

🖱️ Mouse Tracking

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

✍️ Note: Mouse input requires no screen buffer.

view 11
screen 80, 30, 0

⚙️ FIX and TIMES

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!

📝 Full Wide & Greek-native support with fix command

Hobby BASIC is fully Wide-native, supporting Greek identifiers and keywords. To use Greek keywords in your code,
first declare them with the fix command, linking the Greek word to the corresponding English command.

For example:

! After these mappings, you can write your program using Greek commands directly

ΠΡΟΒΟΛΗ fix  VIEW
ΟΘΟΝΗ   fix  SCREEN
ΧΡΩΜΑ   fix  COLOR
ΣΒΗΣΙΜΟ fix  CLS
ΤΥΠΩΣΕ  fix  PRINT
ΠΑΥΣΗ   fix  PAUSE

ΑΡΧΗ#
ΠΡΟΒΟΛΗ 11
ΟΘΟΝΗ 80, 30, 1000
ΣΒΗΣΙΜΟ
ΧΡΩΜΑ 0, 7
ΤΥΠΩΣΕ "Υποστηρίζω Ελληνικά"
ΠΑΥΣΗ

All source code, tokens, labels, and strings are handled as Wide, enabling case-sensitive Greek and Latin text everywhere.

✍️ Note: To display Greek characters correctly, Hobby BASIC requires a raster font that supports Wide glyphs.

🛠️ DEBUG() Window Examples

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.

🔗 Run Remote Scripts Anywhere

One of Hobby BASIC’s unique features is the ability to run remote .BAS scripts directly from the command line, without needing to download them manually. Try the following in the command line and see what it does.

HB.EXE https://files.catbox.moe/ia9qt7.BAS

Alternatively, you can run remote scripts dynamically from within another .BAS program:

exec "run https://files.catbox.moe/ia9qt7.BAS"

This command fetches the .BAS file from the specified URL, loads it into memory, and executes it in the console.

⚠️ Security Warning: Scripts from remote URLs run with full privileges. Only run code from trusted and verified sources.

🎮 Demo Game

A full Hobby BASIC demo running inside the Windows 10 console.

A full Hobby BASIC demo running inside the Windows 10 console
▶ View source code


    !  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.

    !  Windows 10 & 11 Compatibility:
    !  For the program to function correctly, enable the Use Legacy Console option.
    !  Right-click the app title bar and select Properties.
    !  Enable Use Legacy Console.
    !  Restart the console.

    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
    

📘 About Hobby BASIC

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.
👉 Watch a full video tour on YouTube to see Hobby BASIC in action.

🔚 Conclusion

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.