Basics of Zen C

Description of the page content

Conversion of old BASIC programs to Zen C in order to learn the basics of this language.

Tags:

3D Plot

/*
3D Plot

Original version in BASIC:
    Creative Computing (Morristown, New Jersey, USA), ca. 1980.

This version in Zen C:
    Copyright (c) 2026, Marcos Cruz (programandala.net)
    SPDX-License-Identifier: Fair

Written on 2026-04-18.

Last modified 20260420T1758+0200.
*/

import "std/io.zc"
import "std/math.zc"

fn clear_screen() {
    print "\x1b[2J\x1b[0m\x1b[H"
}

fn print_credits() {
    println "3D Plot\n"
    println "Original version in BASIC:"
    println "    Creative computing (Morristown, New Jersey, USA), ca. 1980.\n"
    println "This version in Zen C:"
    println "    Copyright (c) 2026, Marcos Cruz (programandala.net)"
    println "    SPDX-License-Identifier: Fair\n"
    print "Press the Enter key to start. "
    read_rune()
}

fn a_(z: f64) -> f64 {
    return 30 * Math::exp(-z * z / 100)
}

fn draw() {
    let l: int
    let z: int
    let y1: int
    def WIDTH = 56
    let line: bool[WIDTH]
    for let x: f64 = -30.0; x <= 30.0; x += 1.5 {
        l = 0
        y1 = 5 * Math::floor(Math::sqrt(900.0 - x * x) / 5)
        for y in y1 ..= -y1 step -5 {
            z = 25 + a_(Math::sqrt(x * x + y * y)) - 0.7 * y
            if z > l {
                l = z
                line[z] = true
            }
        }
        for i in 0 ..< line.len {
            if line[i] {
                print "*"
                line[i] = false
            }
            else {
                print " "
            }
        }
        println ""
    }
}

fn main() {
    clear_screen()
    print_credits()
    clear_screen()
    draw()
}

Bagels

/*
Bagels

Original version in BASIC:
    D. Resek, P. Rowe, 1978.
    Creative Computing (Morristown, New Jersey, USA), 1978.

This version in Zen C:
    Copyright (c) 2026, Marcos Cruz (programandala.net)
    SPDX-License-Identifier: Fair

Written on 2026-04-20.

Last modified: 20260421T0015+0200.
*/

import "ctype.h" // tolower
import "std/random.zc"
import "std/utf8.zc"

def ANSI = "\x1B[" // code prefix

fn clear_screen() {
    print "{ANSI}2J{ANSI}0m{ANSI}H"
}

fn typed(prompt: string) -> string {
    print "{prompt}"
    return readln()
}

fn print_credits() {
    clear_screen()
    println "Bagels"
    println "Number guessing game\n"
    println "Original source unknown but suspected to be:"
    println "    Lawrence Hall of Science, U.C. Berkely.\n"
    println "Original version in BASIC:"
    println "    D. Resek, P. Rowe, 1978."
    println "    Creative computing (Morristown, New Jersey, USA), 1978.\n"
    println "This version in Zen C:"
    println "    Copyright (c) 2026, Marcos Cruz (programandala.net)"
    println "    SPDX-License-Identifier: Fair\n"
    typed("Press Enter to read the instructions. ")
}

fn print_instructions() {
    clear_screen()
    println "Bagels"
    println "Number guessing game\n"
    println "I am thinking of a three-digit number that has no two digits the same."
    println "Try to guess it and I will give you clues as follows:\n"
    println "   PICO   - one digit correct but in the wrong position"
    println "   FERMI  - one digit correct and in the right position"
    println "   BAGELS - no digits correct"
    typed("\nPress Enter to start. ")
}

def DIGITS = 3

fn is_any_repeated<T>(array: T[DIGITS]) -> bool {
    for i in 0 ..< DIGITS - 1 {
        for j in i + 1 ..< DIGITS {
            if array[i] == array[j] {
                return true
            }
        }
    }
    return false
}

// Print the given prompt and update the given array with a three-digit number
// from the user.

fn get_input(prompt: string, user_digit: int[DIGITS]) {
    asking:
    loop {
        let input: string = typed(prompt)
        if strlen(input) != DIGITS {
            println "Remember it's a {DIGITS}-digit number."
            continue asking
        }
        for i in 0 ..< DIGITS {
            if Utf8::is_digit(input[i]) {
                user_digit[i] = input[i] - '0'
            } else {
                println "What?"
                continue asking
            }
        }
        if is_any_repeated(user_digit) {
            println "Remember my number has no two digits the same."
            continue asking
        }
        break
    }
}

fn to_lowercase(s: string) -> string {
    for i in 0 .. strlen(s) {
        s[i] = tolower(s[i])
    }
    return s
}

fn is_yes(s: string) -> bool {
    match to_lowercase(s) {
        "ok", "y", "yeah", "yes" => { return true }
        _ => { return false }
    }
}

fn is_no(s: string) -> bool {
    match to_lowercase(s) {
        "n", "no", "nope" => { return true }
        _ => { return false }
    }
}

fn yes(prompt: string) -> bool {
    loop {
        let answer: string = typed(prompt)
        if is_yes(answer) {
            return true
        }
        if is_no(answer) {
            return false
        }
    }
}

fn randomize(digit: int[DIGITS]) {
    let rng = Random::new()
    for let i: int = 0; i < DIGITS; i += 1 {
        choose_digit:
        loop {
            digit[i] = rng.next_int_range(0, 9)
            for let j: int = 0; j < i; j += 1 {
                if i != j && digit[i] == digit[j] {
                    continue choose_digit
                }
            }
            break
        }
    }
}

fn play() {
    def TRIES = 20
    let score: int = 0
    let fermi: int = 0 // counter
    let pico: int = 0 // counter
    let user_number: int[DIGITS]
    loop {
        clear_screen()
        let computer_number: int[DIGITS]
        randomize(computer_number)
        println "O.K.  I have a number in mind."
        for let guess: int = 1; guess <= TRIES; guess += 1 {
            get_input("Guess #{guess:2}: ", user_number)
            fermi = 0
            pico = 0
            for i in 0 ..< DIGITS {
                for j in 0 ..< DIGITS {
                    if user_number[i] == computer_number[j] {
                        if i == j {
                            fermi += 1
                        } else {
                            pico += 1
                        }
                    }
                }
            }
            for _ in 0 ..< pico print "PICO "
            for _ in 0 ..< fermi print "FERMI "
            if pico + fermi == 0 {
                print "BAGELS"
            }
            println ""
            if fermi == DIGITS {
                break
            }
        }
        if fermi == DIGITS {
            println "You got it!!!"
            score += 1
        } else {
            println "Oh well."
            print "That's {TRIES} guesses.  My number was "
            for i in 0 ..< DIGITS {
                print "{computer_number[i]}"
            }
            println "."
        }
        if !yes("Play again? ") {
            break
        }
    }
    if score != 0 {
        println "A {score}-point bagels, buff!!"
    }
    println "Hope you had fun.  Bye."
}

fn main() {
    print_credits()
    print_instructions()
    play()
}

Diamond

/*
Diamond

Original version in BASIC:
    Example included in Vintage BASIC 1.0.3.
    http://www.vintage-basic.net

This version in Zen C:
    Copyright (c) 2026, Marcos Cruz (programandala.net)
    SPDX-License-Identifier: Fair

Written on 2026-04-18.

Last modified 20260420T1758+0200.
*/

def LINES = 17

fn main() {
    for i in 1 ..< LINES / 2 + 2 {
        for _ in 1 ..< (LINES + 1) / 2 - i + 2 {
            print " "
        }
        for _ in 1 ..< i * 2 {
            print "*"
        }
        println ""
    }
    for i in 1 ..< LINES / 2 + 1 {
        for _ in 0 ..< i + 1 {
            print " "
        }
        for _ in 1 ..< ((LINES + 1) / 2 - i) * 2 {
            print "*"
        }
        println ""
    }
}

Math

/*
Math

Original version in BASIC:
    Example included in Vintage BASIC 1.0.3.
    http://www.vintage-basic.net

This version in Zen C:
    Copyright (c) 2026, Marcos Cruz (programandala.net)
    SPDX-License-Identifier: Fair

Written on 2026-04-21.

Last modified: 20260421T1401+0200.
*/

import "std/math.zc"

fn sign(n: f64) -> f64 {
    return (n > 0) ? 1 : (n < 0) ? -1 : 0;
}

fn main() {
    let n: f64
    ? "Enter a number: " (n)
    println "ABS({n}) -> Math::abs({n}) -> {Math::abs(n)}"
    println "ATN({n}) -> Math::atan({n}) -> {Math::atan(n)}"
    println "COS({n}) -> Math::cos({n}) -> {Math::cos(n)}"
    println "EXP({n}) -> Math::exp({n}) -> {Math::exp(n)}"
    println "INT({n}) -> (int){n} -> {(int)n}"
    println "LOG({n}) -> Math::log({n}) -> {Math::log(n)}"
    println "SGN({n}) -> sign({n}) /* ad hoc function */ -> {sign(n)}"
    println "SQR({n}) -> Math::sqrt({n}) -> {Math::sqrt(n)}"
    println "TAN({n}) -> Math::tan({n}) -> {Math::tan(n)}"
}

Name

/*
Name

Original version in BASIC:
    Example included in Vintage BASIC 1.0.3.
    http://www.vintage-basic.net

This version in Zen C:
    Copyright (c) 2026, Marcos Cruz (programandala.net)
    SPDX-License-Identifier: Fair

Written on 2026-04-19/20.

Last modified: 20260420T2001+0200.
*/

fn typed(prompt: string) -> string {
    print "{prompt}"
    return readln()
}

fn typed_int(prompt: string) -> int {
    def NUMBER_BASE = 10
    def END_OF_STRING = '\0'
    loop {
        let input: string = typed(prompt)
        defer free(input)
        let end_pointer: string
        let number: int = strtol(input, &end_pointer, NUMBER_BASE)
        if *end_pointer != END_OF_STRING {
            println "Number expected."
        } else {
            return number
        }
    }
}

fn main() {
    let name: string = typed("What is your name? ")
    defer free(name)
    let number: int = typed_int("Enter a number: ")
    for _ in 0 ..< number {
        println "Hello, {name}!"
    }
}

Poetry

/*
Poetry

Original version in BASIC:
    Unknown author.
    Modified and reworked by Jim Bailey, Peggy Ewing, and Dave Ahl at DEC.
    Published in "BASIC Computer Games", Creative Computing (Morristown, New Jersey, USA), 1978.
    https://archive.org/details/Basic_Computer_Games_Microcomputer_Edition_1978_Creative_Computing
    https://github.com/chaosotter/basic-games/tree/master/games/BASIC%20Computer%20Games/Poetry
    http://vintage-basic.net/games.html

This improved remake in Zen C:
    Copyright (c) 2026, Marcos Cruz (programandala.net)
    SPDX-License-Identifier: Fair

Written on 2026-04-20.

Last modified: 20260521T2359+0200.
*/

import "std/random.zc"
import "std/time.zc"

def BLACK        = 0
def RED          = 1
def GREEN        = 2
def YELLOW       = 3
def BLUE         = 4
def MAGENTA      = 5
def CYAN         = 6
def WHITE        = 7
def NORMAL_COLOR = 9

def FOREGROUND   = 30 // color modifier
def BACKGROUND   = 40 // color modifier
def BRIGHT       = 60 // color modifier

def NORMAL_STYLE = 0
def BOLD         = 1
def DIM          = 2
def ITALIC       = 3
def UNDERLINE    = 4
def BLINK        = 5
def OVERLINE     = 6
def INVERT       = 7
def HIDDEN       = 8
def STRIKE       = 9

def OFF          = 20 // style modifier

def INPUT_INK = BRIGHT + GREEN + FOREGROUND
def TITLE_INK = BRIGHT + RED + FOREGROUND

def ANSI = "\x1B[" // code prefix

fn clear_screen() {
    print "{ANSI}2J{ANSI}0m{ANSI}H"
}

fn in_ansi(attribute: int) -> string {
    return "{ANSI}{attribute}m"
}

fn colorized(s: string, attribute: int) -> string {
    return "{in_ansi(attribute)}{s}{in_ansi(NORMAL_STYLE)}"
}

fn typed(prompt: string) -> string {
    print "{colorized(prompt, INPUT_INK)}"
    return readln()
}

fn wait(prompt: string) {
    free(typed(prompt))
}

fn print_credits() {
    println "{colorized(\"Poetry\", TITLE_INK)}"
    println "\nOriginal version in BASIC:"
    println "    Unknown author."
    println "    Published in \"BASIC Computer Games\","
    println "    Creative Computing (Morristown, New Jersey, USA), 1978.\n"

    println "This improved remake in Zen C:"
    println "    Copyright (c) 2026, Marcos Cruz (programandala.net)"
    println "    SPDX-License-Identifier: Fair"
}

fn is_even(n: int) -> bool {
    return n % 2 == 0
}

fn play() {
    def max_phrases_and_verses = 20

    // counters:
    let action: int = 0
    let phrase: int = 0
    let phrases_and_verses: int = 0
    let verse_chunks: int = 0

    let rng = Random::new()

    verse:
    loop {
        let manage_the_verse_continuation: bool = true
        let maybe_add_comma: bool = true

        match action {
            0, 1 => {
                match phrase {
                    0 => { print "MIDNIGHT DREARY" }
                    1 => { print "FIERY EYES" }
                    2 => { print "BIRD OR FIEND" }
                    3 => { print "THING OF EVIL" }
                    4 => { print "PROPHET" }
                }
            }
            2 => {
                match phrase {
                    0 => {
                        print "BEGUILING ME"
                        verse_chunks = 2
                    }
                    1 => {
                        print "THRILLED ME"
                    }
                    2 => {
                        print "STILL SITTING…"
                        maybe_add_comma = false
                    }
                    3 => {
                        print "NEVER FLITTING"
                        verse_chunks = 2
                    }
                    4 => {
                        print "BURNED"
                    }
                }
            }
            3 => {
                match phrase {
                    0 => { print "AND MY SOUL" }
                    1 => { print "DARKNESS THERE" }
                    2 => { print "SHALL BE LIFTED" }
                    3 => { print "QUOTH THE RAVEN" }
                    4 => {
                        if verse_chunks != 0 {
                            print "SIGN OF PARTING"
                        }
                    }
                }
            }
            4 => {
                match phrase {
                    0 => { print "NOTHING MORE" }
                    1 => { print "YET AGAIN" }
                    2 => { print "SLOWLY CREEPING" }
                    3 => { print "…EVERMORE" }
                    4 => { print "NEVERMORE" }
                }
            }
            5 => {
                action = 0
                println ""
                if phrases_and_verses > max_phrases_and_verses {
                    println ""
                    verse_chunks = 0
                    phrases_and_verses = 0
                    action = 2
                    continue verse
                } else {
                    manage_the_verse_continuation = false
                }
            }
        }

        if manage_the_verse_continuation {
            Time::sleep(Duration::from_ms(250))

            if maybe_add_comma && !(verse_chunks == 0 || rng.next_double() > 0.19) {
                print ","
                verse_chunks = 2
            }

            if rng.next_double() > 0.65 {
                println ""
                verse_chunks = 0
            } else {
                print " "
                verse_chunks += 1
            }
        }

        action += 1
        phrase = rng.next_int_range(0, 4)
        phrases_and_verses += 1

        if !(verse_chunks > 0 || is_even(action)) {
            print "     "
        }
    }
}

fn main() {
    clear_screen()
    print_credits()
    wait("\nPress the Enter key to start. ")
    clear_screen()
    play()
}

Russian Roulette

/*
Russian Roulette

Original version in BASIC:
    Creative Computing (Morristown, New Jersey, USA), ca. 1980.

This version in Zen C:
    Copyright (c) 2026, Marcos Cruz (programandala.net)
    SPDX-License-Identifier: Fair

Written on 2026-04-20.

Last modified 20260420T2012+0200.
*/

import "std/random.zc"

def ANSI = "\x1B[" // code prefix

fn clear_screen() {
    print "{ANSI}2J{ANSI}0m{ANSI}H"
}

fn wait() {
    print "Press enter to start. "
    readln()
}

fn print_credits() {
    clear_screen()
    println "Russian Roulette\n"
    println "Original version in BASIC:"
    println "    Creative computing (Morristown, New Jersey, USA), ca. 1980.\n"
    println "This version in Zen C:"
    println "    Copyright (c) 2026, Marcos Cruz (programandala.net)"
    println "    SPDX-License-Identifier: Fair\n"
    wait()
}

fn print_instructions() {
    clear_screen()
    println "Here is a revolver."
    println "Type \"f\" to spin chamber and pull trigger."
    println "Type \"g\" to give up, and play again."
    println "Type \"q\" to quit.\n"
}

fn play() -> bool {
    let rng = Random::new()
    let times: int = 0
    loop { // game
        print_instructions()
        times = 0
        loop { // turn
            match readln() {
                "f" => { // fire
                    if rng.next_int_range(0, 99) > 83 {
                        println "Bang! You're dead!"
                        println "Condolences will be sent to your relatives."
                        break
                    } else {
                        times += 1
                        if times > 10 {
                            println "You win!"
                            println "Let someone else blow his brains out."
                            break
                        } else {
                            println "Click."
                        }
                    }
                }
                "g" => { // give up
                    println "Chicken!"
                    break
                }
                "q" => { // quit
                    return false
                }
            }
        }
        wait()
    }
    return true // play again, do not quit
}

fn main() {
    print_credits()
    while play() {}
    println "Bye!"
}

Sine Wave

/*
Sine Wave

Original version in BASIC:
    Creative Computing (Morristown, New Jersey, USA), ca. 1980.

This version in Zen C:
    Copyright (c) 2026, Marcos Cruz (programandala.net)
    SPDX-License-Identifier: Fair

Written on 2026-04-19.

Last modified 20260420T1759+0200.
*/

import "std/io.zc"
import "std/math.zc"

fn clear_screen() {
    print "\x1b[2J\x1b[0m\x1b[H"
}

fn print_credits() {
    println "Sine Wave\n"
    println "Original version in BASIC:"
    println "    Creative computing (Morristown, New Jersey, USA), ca. 1980.\n"
    println "This version in Zen C:"
    println "    Copyright (c) 2026, Marcos Cruz (programandala.net)"
    println "    SPDX-License-Identifier: Fair\n"
    print "Press Enter to start the program. "
    read_rune()
}

fn draw() {
    let word: string[2]
    print "Enter the first word:  "
    word[0] = readln()
    print "Enter the second word: "
    word[1] = readln()
    defer {
        free(word[0])
        free(word[1])
    }
    clear_screen()

    let even: bool = false
    for let angle: f64 = 0.0; angle <= 40.0; angle += 0.25 {
        for _ in 0 ..< Math::floor(26.0 + 25.0 * Math::sin(angle)) {
            print " "
        }
        println "{word[even]}"
        even = !even
    }
}

fn main() {
    clear_screen()
    print_credits()
    clear_screen()
    draw()
}

Slots

/*
Slots
    A slot machine simulation.

Original version in BASIC:
    Creative Computing (Morristown, New Jersey, USA).
    Produced by Fred Mirabelle and Bob Harper on 1973-01-29.

This version in Zen C:
    Copyright (c) 2026, Marcos Cruz (programandala.net)
    SPDX-License-Identifier: Fair

Written on 2026-04-20.

Last modified 20260421T1040+0200.
*/

import "std/math.zc"
import "std/random.zc"

def BLACK        = 0
def RED          = 1
def GREEN        = 2
def YELLOW       = 3
def BLUE         = 4
def MAGENTA      = 5
def CYAN         = 6
def WHITE        = 7
def NORMAL_COLOR = 9

def FOREGROUND   = 30 // color modifier
def BACKGROUND   = 40 // color modifier
def BRIGHT       = 60 // color modifier

def NORMAL_STYLE = 0
def BOLD         = 1
def DIM          = 2
def ITALIC       = 3
def UNDERLINE    = 4
def BLINK        = 5
def OVERLINE     = 6
def INVERT       = 7
def HIDDEN       = 8
def STRIKE       = 9

def OFF          = 20 // style modifier

def ANSI = "\x1B[" // code prefix

fn in_ansi(attribute: int) -> string {
    return "{ANSI}{attribute}m"
}

fn colorized(s: string, attribute: int) -> string {
    return "{in_ansi(attribute)}{s}{in_ansi(NORMAL_STYLE)}"
}

fn clear_screen() {
    print "{ANSI}2J{ANSI}0m{ANSI}H"
}

fn hide_cursor() {
    print "{ANSI}?25l"
}

fn show_cursor() {
    print "{ANSI}?25h"
}

fn set_cursor_position(y: int, x: int) {
    print "{ANSI}{y};{x}H"
}

fn move_cursor_home() {
    set_cursor_position(0, 0)
}

def IMAGES = 6

let image: const string[IMAGES] = [" BAR  ", " BELL ", "ORANGE", "LEMON ", " PLUM ", "CHERRY"]
def BAR = 0 // position of "BAR" in `image`.

def MAX_BET = 100
def MIN_BET = 1

fn typed(prompt: string) -> string {
    print "{prompt}"
    return readln()
}

fn typed_int(prompt: string) -> int {
    def NUMBER_BASE = 10
    def END_OF_STRING = '\0'
    loop {
        let input: string = typed(prompt)
        defer free(input)
        let end_pointer: string
        let number: int = strtol(input, &end_pointer, NUMBER_BASE)
        if *end_pointer != END_OF_STRING {
            println "Number expected."
        } else {
            return number
        }
    }
}

fn print_credits() {
    clear_screen()
    println "Slots"
    println "A slot machine simulation.\n"
    println "Original version in BASIC:"
    println "    Creative computing (Morristown, New Jersey, USA)."
    println "    Produced by Fred Mirabelle and Bob Harper on 1973-01-29.\n"
    println "This version in Zen C:"
    println "    Copyright (c) 2026, Marcos Cruz (programandala.net)"
    println "    SPDX-License-Identifier: Fair\n"
    typed("Press enter for instructions. ")
}

fn print_instructions() {
    clear_screen()
    println "You are in the H&M casino, in front of one of our"
    println "one-arm bandits. Bet from {MIN_BET} to {MAX_BET} USD (or 0 to quit).\n"
    typed("Press enter to start. ")
}

fn won(prize: int, bet: int) -> int {
    match prize {
          2 => { println "DOUBLE!" }
          5 => { println "*DOUBLE BAR*" }
         10 => { println "**TOP DOLLAR**" }
        100 => { println "***JACKPOT***" }
    }
    println "You won!"
    return (prize + 1) * bet
}

fn print_standings(usd: int) {
    println "Your standings are {usd} USD."
}

let color: const int[IMAGES] = [
    WHITE + FOREGROUND,
    CYAN + FOREGROUND,
    YELLOW + FOREGROUND,
    BRIGHT + YELLOW + FOREGROUND,
    BRIGHT + WHITE + FOREGROUND,
    BRIGHT + RED + FOREGROUND,
]

def REELS = 3
let reel: [int; REELS] // zero-initialized

fn print_reels() {
    move_cursor_home()
    for i in 0 ..< REELS {
        print "[{colorized(image[reel[i]], color[reel[i]])}] "
    }
    println ""
}

fn init_reels() {
    let rng = Random::new()
    for i in 0 ..< REELS {
        reel[i] = rng.next_int_range(0, IMAGES - 1)
    }
}

fn spin_reels() {
    hide_cursor()
    for spin in 0 ..< 24000 {
        init_reels()
        print_reels()
    }
    show_cursor()
}

fn count_of_images(an_image: int) -> int {
    let count: int = 0
    for r in reel {
        count += r == an_image ? 1 : 0
    }
    return count
}

fn play() {
    let standings: int = 0
    let bet: int = 0
    init_reels()
    play:
    loop {
        loop { // bet
            clear_screen()
            print_reels()
            bet = typed_int("Your bet (or 0 to quit): ")
            if bet > MAX_BET {
                println "House limits are {MAX_BET} USD."
                typed("Press enter to try again. ")
            } else if bet < MIN_BET {
                if typed("Type \"q\" to confirm you want to quit. ") == "q" {
                    break play
                }
            } else {
                break
            }
        }
        clear_screen()
        spin_reels()
        let bars: int = count_of_images(BAR)
        let equals: int = 0
        for i in 0 ..< IMAGES {
            equals = Math::max(equals, count_of_images(i))
        }
        if equals == 3 {
            if bars == 3 {
                standings += won(100, bet)
            } else {
                standings += won(10, bet)
            }
        } else if equals == 2 {
            if bars == 2 {
                standings += won(5, bet)
            } else {
                standings += won(2, bet)
            }
        } else {
            println "You lost."
            standings -= bet
        }
        print_standings(standings)
        typed("Press enter to continue. ")
    }
    print_standings(standings)
    if standings < 0 {
        println "Pay up!  Please leave your money on the terminal."
    } else if standings == 0 {
        println "Hey, you broke even."
    } else {
        println "Collect your winnings from the H&M cashier."
    }
}

fn main() {
    print_credits()
    print_instructions()
    play()
}

Stars

/*
Stars

Original version in BASIC:
    Example included in Vintage BASIC 1.0.3.
    http://www.vintage-basic.net

This version in Zen C:
    Copyright (c) 2026, Marcos Cruz (programandala.net)
    SPDX-License-Identifier: Fair

Written on 2026-04-20.

Last modified: 20260420T2012+0200.
*/

import "ctype.h" // tolower

fn typed(prompt: string) -> string {
    print "{prompt}"
    return readln()
}

fn typed_int(prompt: string) -> int {
    def NUMBER_BASE = 10
    def END_OF_STRING = '\0'
    loop {
        let input: string = typed(prompt)
        defer free(input)
        let end_pointer: string
        let number: int = strtol(input, &end_pointer, NUMBER_BASE)
        if *end_pointer != END_OF_STRING {
            println "Number expected."
        } else {
            return number
        }
    }
}

fn to_lowercase(s: string) -> string {
    for i in 0 .. strlen(s) {
        s[i] = tolower(s[i])
    }
    return s
}

fn main() {
    print "What is your name? "
    let name: string = readln()
    defer free(name)
    println "Hello, {name}."
    loop {
        let stars: i64 = typed_int("How many stars do you want? ")
        for _ in 0 .. stars {
            print "*"
        }
        println ""
        print "Do you want more stars? "
        let answer: string = to_lowercase(readln()) // XXX TODO trim
        defer free(answer)
        match answer {
            "ok", "y", "yeah", "yes" => {},
            _ => { break }
        }
    }
}

Related pages

Basics off
Metaproject about the "Basics of…" projects.
Basics of 8th
Conversion of old BASIC programs to 8th in order to learn the basics of this language.
Basics of Ada
Conversion of old BASIC programs to Ada in order to learn the basics of this language.
Basics of Arturo
Conversion of old BASIC programs to Arturo in order to learn the basics of this language.
Basics of C#
Conversion of old BASIC programs to C# in order to learn the basics of this language.
Basics of C3
Conversion of old BASIC programs to C3 in order to learn the basics of this language.
Basics of Chapel
Conversion of old BASIC programs to Chapel in order to learn the basics of this language.
Basics of Clojure
Conversion of old BASIC programs to Clojure in order to learn the basics of this language.
Basics of Crystal
Conversion of old BASIC programs to Crystal in order to learn the basics of this language.
Basics of D
Conversion of old BASIC programs to D in order to learn the basics of this language.
Basics of Elixir
Conversion of old BASIC programs to Elixir in order to learn the basics of this language.
Basics of F#
Conversion of old BASIC programs to F# in order to learn the basics of this language.
Basics of Factor
Conversion of old BASIC programs to Factor in order to learn the basics of this language.
Basics of FreeBASIC
Conversion of old BASIC programs to FreeBASIC in order to learn the basics of this language.
Basics of Gleam
Conversion of old BASIC programs to Gleam in order to learn the basics of this language.
Basics of Go
Conversion of old BASIC programs to Go in order to learn the basics of this language.
Basics of Hare
Conversion of old BASIC programs to Hare in order to learn the basics of this language.
Basics of Haxe
Conversion of old BASIC programs to Haxe in order to learn the basics of this language.
Basics of Icon
Conversion of old BASIC programs to Icon in order to learn the basics of this language.
Basics of Io
Conversion of old BASIC programs to Io in order to learn the basics of this language.
Basics of Janet
Conversion of old BASIC programs to Janet in order to learn the basics of this language.
Basics of Julia
Conversion of old BASIC programs to Julia in order to learn the basics of this language.
Basics of Kotlin
Conversion of old BASIC programs to Kotlin in order to learn the basics of this language.
Basics of Lobster
Conversion of old BASIC programs to Lobster in order to learn the basics of this language.
Basics of Lua
Conversion of old BASIC programs to Lua in order to learn the basics of this language.
Basics of Nature
Conversion of old BASIC programs to Nature in order to learn the basics of this language.
Basics of Neat
Conversion of old BASIC programs to Neat in order to learn the basics of this language.
Basics of Neko
Conversion of old BASIC programs to Neko in order to learn the basics of this language.
Basics of Nelua
Conversion of old BASIC programs to Nelua in order to learn the basics of this language.
Basics of Nim
Conversion of old BASIC programs to Nim in order to learn the basics of this language.
Basics of Nit
Conversion of old BASIC programs to Nit in order to learn the basics of this language.
Basics of Oberon-07
Conversion of old BASIC programs to Oberon-07 in order to learn the basics of this language.
Basics of OCaml
Conversion of old BASIC programs to OCaml in order to learn the basics of this language.
Basics of Odin
Conversion of old BASIC programs to Odin in order to learn the basics of this language.
Basics of Pike
Conversion of old BASIC programs to Pike in order to learn the basics of this language.
Basics of Pony
Conversion of old BASIC programs to Pony in order to learn the basics of this language.
Basics of Python
Conversion of old BASIC programs to Python in order to learn the basics of this language.
Basics of Racket
Conversion of old BASIC programs to Racket in order to learn the basics of this language.
Basics of Raku
Conversion of old BASIC programs to Raku in order to learn the basics of this language.
Basics of Retro
Conversion of old BASIC programs to Retro in order to learn the basics of this language.
Basics of Rexx
Conversion of old BASIC programs to Rexx in order to learn the basics of this language.
Basics of Ring
Conversion of old BASIC programs to Ring in order to learn the basics of this language.
Basics of Rust
Conversion of old BASIC programs to Rust in order to learn the basics of this language.
Basics of Scala
Conversion of old BASIC programs to Scala in order to learn the basics of this language.
Basics of Scheme
Conversion of old BASIC programs to Scheme in order to learn the basics of this language.
Basics of Styx
Conversion of old BASIC programs to Styx in order to learn the basics of this language.
Basics of Swift
Conversion of old BASIC programs to Swift in order to learn the basics of this language.
Basics of V
Conversion of old BASIC programs to V in order to learn the basics of this language.
Basics of Vala
Conversion of old BASIC programs to Vala in order to learn the basics of this language.
Basics of Zig
Conversion of old BASIC programs to Zig in order to learn the basics of this language.

External related links