Basics of Zen C
Descrition del contenete del págine
Conversion de old BASIC-programas a Zen C por aprender lu elementari de ti-ci lingue.
Etiquettes:
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 }
}
}
}
