Basics of Pike

Priskribo de la ĉi-paĝa enhavo

Konverto de malnovaj BASIC-programoj al Pike por lerni la fundamentojn de ĉi-tiu lingvo.

Etikedoj:

3D Plot

#! /usr/bin/env pike

// 3D Plot

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

// This version in Pike:
//  Copyright (c) 2024, Marcos Cruz (programandala.net)
//  SPDX-License-Identifier: Fair
//
// Written on 2024-12-17.
//
// Last modified: 20250311T0155+0100.

constant SPACE = " ";
constant DOT = "*";
constant WIDTH = 56;

void clear_screen() {
    write("\x1B[0;0H\x1B[2J");
}

void prompt(string s) {
    write(s);
    Stdio.stdin->gets();
}

void print_credits() {
    write("3D Plot\n\n");
    write("Original version in BASIC:\n");
    write("    Creative computing (Morristown, New Jersey, USA), ca. 1980.\n\n");
    write("This version in Pike:\n");
    write("    Copyright (c) 2024, Marcos Cruz (programandala.net)\n");
    write("    SPDX-License-Identifier: Fair\n\n");
    prompt("Press Enter to start. ");
}

float a(float z) {
    return 30.0 * exp(-z * z / 100.0);
}

void draw() {

    int l = 0;
    int z = 0;
    int y1 = 0;

    array(string) line = allocate(WIDTH);

    for (float x = -30.0; x <= 30.0; x += 1.5) {

        for (int i = 0; i < WIDTH; i += 1)
            line[i] = SPACE;

        l = 0;
        y1 = 5 * (int) (sqrt(900.0 - x * x) / 5.0);

        for (int y = y1; y >= -y1; y += -5) {
            z = (int) (25.0 + a(sqrt(x * x + (float) (y * y))) - 0.7 * (float) y);
            if (z > l) {
                l = z;
                line[z] = DOT;
            }
        } // y loop

        for (int pos = 0; pos < WIDTH; pos += 1)
            write(line[pos]);

        write("\n");

    } // x loop

}

void main() {
    clear_screen();
    print_credits();
    clear_screen();
    draw();
}

Bagels

#!/usr/bin/env pike

// Bagels

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

// This version in Pike:
//  Copyright (c) 2025, Marcos Cruz (programandala.net)
//  SPDX-License-Identifier: Fair
//
// Written on 2025-03-10.
//
// Last modified: 20250324T1737+0100.

// Terminal {{{1
// =============================================================================

constant NORMAL_STYLE = 0;

void move_cursor_home() {
    write("\x1B[H");
}

void set_style(int style) {
    write("\x1B[%dm", style);
}

void reset_attributes() {
    set_style(NORMAL_STYLE);
}

void erase_screen() {
    write("\x1B[2J");
}

void clear_screen() {
    erase_screen();
    reset_attributes();
    move_cursor_home();
}

// Credits and instructions {{{1
// =============================================================================

// Clear the screen, display the credits and wait for a keypress.
//
void print_credits() {
    clear_screen();
    write("Bagels\n");
    write("Number guessing game\n\n");
    write("Original source unknown but suspected to be:\n");
    write("    Lawrence Hall of Science, U.C. Berkely.\n\n");
    write("Original version in BASIC:\n");
    write("    D. Resek, P. Rowe, 1978.\n");
    write("    Creative computing (Morristown, New Jersey, USA), 1978.\n\n");
    write("This version in Pike:\n");
    write("    Copyright (c) 2025, Marcos Cruz (programandala.net)\n");
    write("    SPDX-License-Identifier: Fair\n\n");
    accept_string("Press Enter to read the instructions. ");
}

// Clear the screen, print the instructions and wait for a keypress.
//
void print_instructions() {
    clear_screen();
    write("Bagels\n");
    write("Number guessing game\n\n");
    write("I am thinking of a three-digit number that has no two digits the same.\n");
    write("Try to guess it and I will give you clues as follows:\n\n");
    write("   PICO   - one digit correct but in the wrong position\n");
    write("   FERMI  - one digit correct and in the right position\n");
    write("   BAGELS - no digits correct\n\n");
    accept_string("Press Enter to start. ");
}

// User input {{{1
// =============================================================================

string accept_string(string prompt) {
    write(prompt);
    return Stdio.stdin->gets();
}

// Return `true` if the given string is "yes" or a synonym.
//
bool is_yes(string s) {
    switch(lower_case(s)) {
        case "ok":
        case "y":
        case "yeah":
        case "yes":
            return true;
        default:
            return false;
    }
}

// Return `true` if the given string is "no" or a synonym.
//
bool is_no(string s) {
    switch(lower_case(s)) {
        case "n":
        case "no":
        case "nope":
            return true;
        default:
            return false;
    }
}

// Print the given prompt, wait until the user enters a valid yes/no string,
// and return `true` for "yes" or `false` for "no".
//
bool yes(string prompt) {
    while (true) {
        string answer = accept_string(prompt);
        if (is_yes(answer)) {
            return true;
        }
        if (is_no(answer)) {
            return false;
        }
    }
}

// Main {{{1
// =============================================================================

constant DIGITS = 3;

bool is_digit(int ascii_code) {
    return (ascii_code >= '0') && (ascii_code <= '9');
}

// Print the given prompt and return an array with a three-digit number type by
// the user.
//
array(int) get_input(string prompt) {
    array(int) user_digit = allocate(DIGITS);
    constant ASCII_0 = '0';
    get_loop: while (true) {
        string input = accept_string(prompt);
        if (sizeof(input) != DIGITS) {
            write("Remember it's a %d-digit number.\n", DIGITS);
            continue get_loop;
        }
        for (int pos = 0; pos < sizeof(input); pos += 1) {
            int digit = input[pos];
            if (is_digit(digit)) {
                user_digit[pos] = digit - ASCII_0;
            } else {
                write("What?\n");
                continue get_loop;
            }
        }
        if (is_any_repeated(user_digit)) {
            write("Remember my number has no two digits the same.\n");
            continue get_loop;
        }
        break;
    }
    return user_digit;
}

// Return three random digits.
//
array(int) random_number() {
    array(int) random_digit = allocate(DIGITS);
    for (int i = 0; i < DIGITS; i += 1) {
        digit_loop: while (true) {
            random_digit[i] = random(10);
            for (int j = 0; j < i; j += 1) {
                if (i != j && random_digit[i] == random_digit[j]) {
                    continue digit_loop;
                }
            }
            break;
        }
    }
    return random_digit;
}

// Return `true` if any of the given numbers is repeated; otherwise return
// `false`.
//
bool is_any_repeated(array(int) numbers) {
    array(int) filtered_numbers = Array.uniq(numbers);
    return !equal(filtered_numbers, numbers);
}

// Init and run the game loop.
//
void play() {
    constant TRIES = 20;
    int score = 0;
    int fermi = 0; // counter
    int pico = 0; // counter
    array(int) computer_number = allocate(DIGITS);
    array(int) user_number = allocate(DIGITS);
    while (true) {
        clear_screen();
        array(int) computer_number = random_number();
        write("O.K.  I have a number in mind.\n");
        for (int guess = 1; guess <= TRIES; guess += 1) {
            // XXX TMP
            // write("My number: ");
            // for (int i = 0; i < DIGITS; i += 1) {
            //  write("%d", computer_number[i]);
            // }
            // write("\n");
            user_number = get_input(sprintf("Guess #%02d: ", guess));
            fermi = 0;
            pico = 0;
            for (int i = 0; i < DIGITS; i += 1) {
                for (int j = 0; j < DIGITS; j += 1) {
                    if (user_number[i] == computer_number[j]) {
                        if (i == j) {
                            fermi += 1;
                        } else {
                            pico += 1;
                        }
                    }
                }
            }
            if (pico + fermi == 0) {
                write("BAGELS\n");
            } else {
                write("%s%s\n", "PICO " * pico, "FERMI " * fermi);
                if (fermi == DIGITS) {
                    break;
                }
            }
        }
        if (fermi == DIGITS) {
            write("You got it!!!\n");
            score += 1;
        } else {
            write("Oh well.\n");
            write("That's %d guesses.  My number was ", TRIES);
            for (int i = 0; i < DIGITS; i += 1) {
                write("%d", computer_number[i]);
            }
            write(".\n");
        }
        if (!yes("Play again? ")) {
            break;
        }
    }
    if (score != 0) {
        write("A %d-point bagels, buff!!\n", score);
    }
    write("Hope you had fun.  Bye.\n");
}

void main() {
    print_credits();
    print_instructions();
    play();
}

Bug

#!/usr/bin/env pike

// Bug

// Original version in BASIC:
//  Brian Leibowitz, 1978.
//  Creative Computing (Morristown, New Jersey, USA), 1978.

// This version in Pike:
//  Copyright (c) 2025, Marcos Cruz (programandala.net)
//  SPDX-License-Identifier: Fair
//
// Written on 2025-03-10.
//
// Last modified: 20250312T1154+0100.

// Data {{{1
// =============================================================================

class Bug {
    bool body;
    bool neck;
    bool head;
    int feelers;
    string feeler_type;
    bool tail;
    int legs;
}

class Player {
    string pronoun;
    string possessive;
    Bug bug;
}

Player computer = Player();
Player human = Player();

void init_data() {

    computer.pronoun = "I";
    computer.possessive = "My";
    computer.bug = Bug();
    computer.bug.body = false;
    computer.bug.neck = false;
    computer.bug.head = false;
    computer.bug.feelers = 0;
    computer.bug.feeler_type = "F";
    computer.bug.tail = false;
    computer.bug.legs = 0;

    human.pronoun = "you";
    human.possessive = "Your";
    human.bug = Bug();
    human.bug.body = false;
    human.bug.neck = false;
    human.bug.head = false;
    human.bug.feelers = 0;
    human.bug.feeler_type = "A";
    human.bug.tail = false;
    human.bug.legs = 0;
}

enum Bug_part {
    BODY = 1,
    NECK,
    HEAD,
    FEELER,
    TAIL,
    LEG,
}

constant FIRST_PART = BODY;
constant LAST_PART = LEG;

int part_quantity(Bug_part part) {
    switch (part) {
        case BODY: return 1;
        case NECK: return 1;
        case HEAD: return 1;
        case FEELER: return 2;
        case TAIL: return 1;
        case LEG: return 6;
    }
}

string part_name(Bug_part part) {
    switch (part) {
        case BODY: return "body";
        case NECK: return "neck";
        case HEAD: return "head";
        case FEELER: return "feeler";
        case TAIL: return "tail";
        case LEG: return "leg";
    }
}

// Bug body attributes.
//
constant BODY_HEIGHT = 2;
constant FEELER_LENGTH = 4;
constant LEG_LENGTH = 2;
constant MAX_FEELERS = 2;
constant MAX_LEGS = 6;
constant NECK_LENGTH = 2;

// Terminal {{{1
// =============================================================================

constant NORMAL_STYLE = 0;

void move_cursor_home() {
    write("\x1B[H");
}

void move_cursor_up() {
    write("\x1B[1A");
}

void set_style(int style) {
    write("\x1B[%dm", style);
}

void reset_attributes() {
    set_style(NORMAL_STYLE);
}

void erase_screen() {
    write("\x1B[2J");
}

void clear_screen() {
    erase_screen();
    reset_attributes();
    move_cursor_home();
}

// Erase the entire current line and move the cursor to the start of the line.
//
void erase_line() {
    write("\x1B[2K");
}

// User input {{{1
// =============================================================================

string accept_string(string prompt) {
    write(prompt);
    return Stdio.stdin.gets();
}

// Credits and instructions {{{1
// =============================================================================

// Clear the screen, display the credits and wait for a keypress.
//
void print_credits() {
    clear_screen();
    write("Bug\n\n");
    write("Original version in BASIC:\n");
    write("    Brian Leibowitz, 1978.\n");
    write("    Creative computing (Morristown, New Jersey, USA), 1978.\n\n");
    write("This version in Pike:\n");
    write("    Copyright (c) 2025, Marcos Cruz (programandala.net)\n");
    write("    SPDX-License-Identifier: Fair\n\n");
    accept_string("Press Enter to read the instructions. ");
}

constant INSTRUCTIONS =
"The object is to finish your bug before I finish mine. Each number\n" +
"stands for a part of the bug body.\n" +
"\n" +
"I will roll the die for you, tell you what I rolled for you, what the\n" +
"number stands for, and if you can get the part. If you can get the\n" +
"part I will give it to you. The same will happen on my turn.\n" +
"\n" +
"If there is a change in either bug I will give you the option of\n" +
"seeing the pictures of the bugs. The numbers stand for parts as\n" +
"follows:\n";

// Clear the screen, print the instructions and wait for a keypress.
//
void print_instructions() {
    clear_screen();
    write("Bug\n\n");
    write("%s\n", INSTRUCTIONS);
    print_parts_table();
    accept_string("\nPress Enter to start. ");
}

// Pseudo-random numbers {{{1
// =============================================================================

// Return a random number from 1 to 6 (inclusive).
//
int dice() {
    return (random(6) + 1);
}

// Main {{{1
// =============================================================================

// Print a table with the description of the bug parts.
//
void print_parts_table() {

    constant COLUMNS = 3;
    constant COLUMN_WIDTH = 8;
    constant COLUMN_SEPARATION = 2;

    string format_string = "%-" + (string) (COLUMN_WIDTH + COLUMN_SEPARATION) + "s";

    // Headers
    array(string) header = ({"Number", "Part", "Quantity"});
    for (int i = 0; i < COLUMNS; i += 1) {
        write(format_string, header[i]);
    }
    write("\n");

    // Rulers
    string ruler = "-" * COLUMN_WIDTH;
    string padding = " " * COLUMN_SEPARATION;
    for (int i = 0; i < COLUMNS; i += 1) {
        write("%s%s", ruler, i == COLUMNS - 1 ? "" : padding);
    }
    write("\n");

    // Data
    for (Bug_part part = FIRST_PART; part <= LAST_PART; part += 1) {
        write(format_string, (string) part);
        string name = String.capitalize(part_name(part));
        write(format_string, name);
        write(format_string, (string) part_quantity(part));
        write("\n");
    }
}

// Print a bug head.
//
void print_head() {
    write("        HHHHHHH\n");
    write("        H     H\n");
    write("        H O O H\n");
    write("        H     H\n");
    write("        H  V  H\n");
    write("        HHHHHHH\n");
}

// Print the given bug.
//
void print_bug(Bug bug) {
    if (bug.feelers > 0) {
        for (int i = 0; i < FEELER_LENGTH; i += 1) {
            write("        ");
            for (int i = 0; i < bug.feelers; i += 1) {
                write(" %s", bug.feeler_type);
            }
            write("\n");
        }
    }
    if (bug.head) {
        print_head();
    }
    if (bug.neck) {
        for (int i = 0; i < NECK_LENGTH; i += 1) {
            write("          N N\n");
        }
    }
    if (bug.body) {
        write("     BBBBBBBBBBBB\n");
        for (int i = 0; i < BODY_HEIGHT; i += 1) {
            write("     B          B\n");
        }
        if (bug.tail) {
            write("TTTTTB          B\n");
        }
        write("     BBBBBBBBBBBB\n");
    }
    if (bug.legs > 0) {
        for (int i = 0; i < LEG_LENGTH; i += 1) {
            write("    ");
            for (int i = 0; i < bug.legs; i += 1) {
                write(" L");
            }
            write("\n");
        }
    }
}

// Return `true` if the given bug is finished; otherwise return `false`.
//
bool finished(Bug bug) {
    return bug.feelers == MAX_FEELERS && bug.tail && bug.legs == MAX_LEGS;
}

// Array to convert a number to its equilavent text.
//
array(string) as_text = ({
    "no",
    "a",
    "two",
    "three",
    "four",
    "five",
    "six" }); // MAX_LEGS

// Return a string containing the given number and noun in their proper form.
//
string plural(int number, string noun) {
    return as_text[number] + " " + noun + ((number > 1) ? "s" : "");
}

// Add the given part to the given player's bug.
//
bool add_part(Bug_part part, Player player) {
    bool changed = false;
    switch (part) {
        case BODY:
            if (player.bug.body) {
                write(", but %s already have a body.\n", player.pronoun);
            } else {
                write("; %s now have a body:\n", player.pronoun);
                player.bug.body = true;
                changed = true;
            }
            break;
        case NECK:
            if (player.bug.neck) {
                write(", but %s already have a neck.\n", player.pronoun);
            } else if (!player.bug.body) {
                write(", but %s need a body first.\n", player.pronoun);
            } else {
                write("; %s now have a neck:\n", player.pronoun);
                player.bug.neck = true;
                changed = true;
            }
            break;
        case HEAD:
            if (player.bug.head) {
                write(", but %s already have a head.\n", player.pronoun);
            } else if (!player.bug.neck) {
                write(", but %s need a a neck first.\n", player.pronoun);
            } else {
                write("; %s now have a head:\n", player.pronoun);
                player.bug.head = true;
                changed = true;
            }
            break;
        case FEELER:
            if (player.bug.feelers == MAX_FEELERS) {
                write(", but %s have two feelers already.\n", player.pronoun);
            } else if (!player.bug.head) {
                write(", but %s need a head first.\n", player.pronoun);
            } else {
                player.bug.feelers += 1;
                write("; %s now have %s", player.pronoun, plural(player.bug.feelers, "feeler"));
                write(":\n");
                changed = true;
            }
            break;
        case TAIL:
            if (player.bug.tail) {
                write(", but %s already have a tail.\n", player.pronoun);
            } else if (!player.bug.body) {
                write(", but %s need a body first.\n", player.pronoun);
            } else {
                write("; %s now have a tail:\n", player.pronoun);
                player.bug.tail = true;
                changed = true;
            }
            break;
        case LEG:
            if (player.bug.legs == MAX_LEGS) {
                write(", but %s have %s feet already.", player.pronoun, as_text[MAX_LEGS]);
            } else if (!player.bug.body) {
                write(", but %s need a body first.\n", player.pronoun);
            } else {
                player.bug.legs += 1;
                write("; %s now have %s", player.pronoun, plural(player.bug.legs, "leg"));
                write(":\n");
                changed = true;
            }
    }
    return changed;
}

// Play one turn for the given player, rolling the dice and updating his bug.
//
void turn(Player player) {
    accept_string("Press Enter to roll the dice. ");
    move_cursor_up();
    erase_line();
    int part = dice();
    string pronoun = String.capitalize(player.pronoun);
    write("%s rolled a %d (%s)", pronoun, part, part_name(part));
    if (add_part(part, player)) {
        write("\n");
        print_bug(player.bug);
    }
    write("\n");
}

// Print a message about the winner.
//
void print_winner() {
    if (finished(human.bug) && finished(computer.bug)) {
        write("Both of our bugs are finished in the same number of turns!\n");
    } else if (finished(human.bug)) {
        write("%s bug is finished.\n", human.possessive);
    } else if (finished(computer.bug)) {
        write("%s bug is finished.\n", computer.possessive);
    }
}

// Return `true` if either bug is finished, i.e. the game ending condition.
//
bool game_over() {
    return finished(human.bug) || finished(computer.bug);
}

// Execute the game loop.
//
void play() {
    clear_screen();
    while (!game_over()) {
        turn(human);
        turn(computer);
    }
    print_winner();
}

void bye() {
    write("I hope you enjoyed the game, play it again soon!!\n");
}

void main() {
    init_data();
    print_credits();
    print_instructions();
    play();
    bye();
}

Bunny

#! /usr/bin/env pike

// Bunny

// Original version in BASIC:
//  Creative Computing (Morristown, New Jersey, USA), 1978.

// This version in Pike:
//  Copyright (c) 2025, Marcos Cruz (programandala.net)
//  SPDX-License-Identifier: Fair
//
// Written on 2025-03-08.
//
// Last modified: 20250310T0301+0100.

void clear_screen() {
    write("\x1B[0;0H\x1B[2J");
}

void press_enter(string prompt) {
    write(prompt);
    Stdio.stdin->gets();
}

void print_credits() {
    write("Bunny\n\n");
    write("Original version in BASIC:\n");
    write("    Creative Computing (Morristown, New Jersey, USA), 1978.\n\n");
    write("This version in Pike:\n");
    write("    Copyright (c) 2025, Marcos Cruz (programandala.net)\n");
    write("    SPDX-License-Identifier: Fair\n\n");
    press_enter("Press Enter to start the program. ");
}

constant WIDTH = 53; // size of the line buffer

array(string) line = ({}); // line buffer

// Init the line buffer.
//
void init_line() {
    for (int column = 0; column < WIDTH; column += 1) {
        line += ({" "});
    }
}

// Clear the line buffer with spaces.
//
void clear_line() {
    for (int column = 0; column < WIDTH; column += 1) {
        line[column] = " ";
    }
}

array(string) letter = ({"B", "U", "N", "N", "Y"});

int LETTERS = sizeof(letter);

constant EOL = -1; // end of line identifier

array(int) data = ({
    1, 2, EOL, 0, 2, 45, 50, EOL, 0, 5, 43, 52, EOL, 0, 7, 41, 52, EOL,
    1, 9, 37, 50, EOL, 2, 11, 36, 50, EOL, 3, 13, 34, 49, EOL, 4, 14,
    32, 48, EOL, 5, 15, 31, 47, EOL, 6, 16, 30, 45, EOL, 7, 17, 29, 44,
    EOL, 8, 19, 28, 43, EOL, 9, 20, 27, 41, EOL, 10, 21, 26, 40, EOL,
    11, 22, 25, 38, EOL, 12, 22, 24, 36, EOL, 13, 34, EOL, 14, 33, EOL,
    15, 31, EOL, 17, 29, EOL, 18, 27, EOL, 19, 26, EOL, 16, 28, EOL,
    13, 30, EOL, 11, 31, EOL, 10, 32, EOL, 8, 33, EOL, 7, 34, EOL, 6,
    13, 16, 34, EOL, 5, 12, 16, 35, EOL, 4, 12, 16, 35, EOL, 3, 12, 15,
    35, EOL, 2, 35, EOL, 1, 35, EOL, 2, 34, EOL, 3, 34, EOL, 4, 33,
    EOL, 6, 33, EOL, 10, 32, 34, 34, EOL, 14, 17, 19, 25, 28, 31, 35,
    35, EOL, 15, 19, 23, 30, 36, 36, EOL, 14, 18, 21, 21, 24, 30, 37, 37,
    EOL, 13, 18, 23, 29, 33, 38, EOL, 12, 29, 31, 33, EOL, 11, 13, 17,
    17, 19, 19, 22, 22, 24, 31, EOL, 10, 11, 17, 18, 22, 22, 24, 24, 29,
    29, EOL, 22, 23, 26, 29, EOL, 27, 29, EOL, 28, 29, EOL });

int data_index = 0;

int datum() {
    return data[data_index++];
}

void draw() {
    init_line();
    while (data_index < sizeof(data)) {
        int first_column = datum();
        if (first_column == EOL) {
            foreach(line, string c) {
                write("%s", c);
            }
            write("\n");
            clear_line();
        } else {
            int last_column = datum();
            for (int column = first_column; column <= last_column; column += 1) {
                line[column] = letter[column % LETTERS];
            }
        }
    }
}

void main() {
    clear_screen();
    print_credits();
    clear_screen();
    draw();
}

Chase

#!/usr/bin/env pike

// Chase

// Original version in BASIC:
//  Anonymous.
//  Published in 1977 in "The Best of Creative Computing", Volume 2.
//  https://www.atariarchives.org/bcc2/showpage.php?page=253

// This version in Pike:
//  Copyright (c) 2025, Marcos Cruz (programandala.net)
//  SPDX-License-Identifier: Fair
//
//  Written on 2025-03-11.
//  Last modified: 20250731T1954+0200.

// Terminal {{{1
// =============================================================================

constant BLACK = 0;
constant RED = 1;
constant GREEN = 2;
constant YELLOW = 3;
constant BLUE = 4;
constant MAGENTA = 5;
constant CYAN = 6;
constant WHITE = 7;
constant DEFAULT = 9;

constant STYLE_OFF = 20;
constant FOREGROUND = 30;
constant BACKGROUND = 40;
constant BRIGHT = 60;

constant NORMAL_STYLE = 0;

void move_cursor_home() {
    write("\x1B[H");
}

void set_cursor_position(int line, int col) {
    write("\x1B[%d;%dH", line, col);
}

void hide_cursor() {
    write("\x1B[?25l");
}

void show_cursor() {
    write("\x1B[?25h");
}

void set_style(int style) {
    write("\x1B[%dm", style);
}

void reset_attributes() {
    set_style(NORMAL_STYLE);
}

void erase_line_to_end() {
    write("\x1B[K");
}

void erase_screen() {
    write("\x1B[2J");
}

void clear_screen() {
    erase_screen();
    reset_attributes();
    move_cursor_home();
}

// Config {{{1
// =============================================================

constant DEFAULT_INK = WHITE + FOREGROUND;
constant INPUT_INK = BRIGHT + GREEN + FOREGROUND;
constant INSTRUCTIONS_INK = YELLOW + FOREGROUND;
constant TITLE_INK = BRIGHT + RED + FOREGROUND;

// Data {{{1
// =============================================================

// Arena

constant ARENA_WIDTH = 20;
constant ARENA_HEIGHT = 10;
constant ARENA_LAST_X = ARENA_WIDTH - 1;
constant ARENA_LAST_Y = ARENA_HEIGHT - 1;
constant ARENA_ROW = 3;

array(array(string)) arena = allocate(ARENA_HEIGHT, allocate(ARENA_WIDTH, ""));

constant EMPTY = " ";
constant FENCE = "X";
constant MACHINE = "m";
constant HUMAN = "@";

constant FENCES = 15; // inner obstacles, not the border

// The end

enum End {
    NOT_YET,
    QUIT,
    ELECTRIFIED,
    KILLED,
    VICTORY
}

End the_end = NOT_YET;

// Machines

constant MACHINES = 5;
constant MACHINES_DRAG = 2; // probability not moving: 0=0%, 1=50%, 2=66%, 3=75%, etc.

array(int) machine_x = allocate(MACHINES);
array(int) machine_y = allocate(MACHINES);
array(bool) operative = allocate(MACHINES);

int destroyed_machines = 0; // counter

// Human

int human_x = 0;
int human_y = 0;

// User input {{{1
// =============================================================

string accept_string(string prompt) {
    write(prompt);
    return Stdio.stdin->gets();
}

string get_string(string prompt) {
    set_style(INPUT_INK);
    string s = accept_string(prompt);
    set_style(DEFAULT_INK);
    return s;
}

void press_enter(string prompt) {
    accept_string(prompt);
}

bool is_yes(string s) {
    switch(lower_case(s)) {
        case "ok":
        case "y":
        case "yeah":
        case "yes":
            return true;
        default:
            return false;
    }
}

bool is_no(string s) {
    switch(lower_case(s)) {
        case "n":
        case "no":
        case "nope":
            return true;
        default:
            return false;
    }
}

// Print the given prompt, wait until the user enters a valid yes/no string,
// and return `true` for "yes" or `false` for "no".
//
bool yes(string prompt) {
    while (true) {
        string answer = get_string(prompt);
        if (is_yes(answer)) {
            return true;
        }
        if (is_no(answer)) {
            return false;
        }
    }
}

// Title, credits and instructions {{{1
// =============================================================

constant TITLE = "Chase";

void print_title() {
    set_style(TITLE_INK);
    write("%s\n", TITLE);
    set_style(DEFAULT_INK);
}

void print_credits() {
    print_title();
    write("\nOriginal version in BASIC:\n");
    write("    Anonymous.\n");
    write("    Published in \"The Best of Creative Computing\", Volume 2, 1977.\n");
    write("    https://www.atariarchives.org/bcc2/showpage.php?page=253\n");
    write("This version in Pike:\n");
    write("    Copyright (c) 2025, Marcos Cruz (programandala.net)\n");
    write("    SPDX-License-Identifier: Fair\n");
}

void print_instructions() {
    print_title();
    set_style(INSTRUCTIONS_INK);
    write("\nYou (%s) are in a high voltage maze with %d\n", HUMAN, MACHINES);
    write("security machines (%s) trying to kill you.\n", MACHINE);
    write("You must maneuver them into the maze (%s) to survive.\n\n", FENCE);
    write("Good luck!\n\n");
    write("The movement commands are the following:\n\n");
    write("    ↖  ↑  ↗\n");
    write("    NW N NE\n");
    write("  ←  W   E  →\n");
    write("    SW S SE\n");
    write("    ↙  ↓  ↘\n");
    write("\nPlus 'Q' to end the game.\n");
    set_style(DEFAULT_INK);
}

// Arena {{{1
// =============================================================

void print_arena() {
    set_cursor_position(ARENA_ROW, 1);
    for (int y = 0; y <= ARENA_LAST_Y; y += 1) {
        for (int x = 0; x <= ARENA_LAST_X; x += 1) {
            write(arena[y][x]);
        }
        write("\n");
    }
}

// If the given arena coordinates `y` and `x` are part of the border arena
// (i.e. its surrounding fence), return `true`, otherwise return `false`.
//
bool is_border(int y, int x) {
    return (y == 0) || (x == 0) || (y == ARENA_LAST_Y) || (x == ARENA_LAST_X);
}

int random_int_in_inclusive_range(int min, int max) {
    return random(max - min) + min;
}

// Place the given string at a random empty position of the arena and return
// the coordinates.
//
array(int) place(string s) {
    int y = 0;
    int x = 0;
    while (true) {
        y = random_int_in_inclusive_range(1, ARENA_LAST_Y - 1);
        x = random_int_in_inclusive_range(1, ARENA_LAST_X - 1);
        if (arena[y][x] == EMPTY) {
            break;
        }
    }
    arena[y][x] = s;
    return ({y, x});
}

// Inhabit the arena with the machines, the inner fences and the human.
//
void inhabit_arena() {
    array(int) coords;
    for (int m = 0; m < MACHINES; m += 1) {
        coords = place(MACHINE);
        machine_y[m] = coords[0];
        machine_x[m] = coords[1];
        operative[m] = true;
    }
    for (int i = 0; i < FENCES; i += 1) {
        place(FENCE);
    }
    coords = place(HUMAN);
    human_y = coords[0];
    human_x = coords[1];
}

// Clean the arena, i.e. empty it and add a surrounding fence.
//
void clean_arena() {
    for (int y = 0; y <= ARENA_LAST_Y; y += 1) {
        for (int x = 0; x <= ARENA_LAST_X; x += 1) {
            arena[y][x] = is_border(y, x) ? FENCE : EMPTY;
        }
    }
}

// Game {{{1
// =============================================================

void init_game() {
    clean_arena();
    inhabit_arena();
    destroyed_machines = 0;
    the_end = NOT_YET;
}

void move_machine(int m) {

    int maybe = 0;

    arena[machine_y[m]][machine_x[m]] = EMPTY;

    maybe = random(2);
    if (machine_y[m] > human_y) {
        machine_y[m] -= maybe;
    } else if (machine_y[m] < human_y) {
        machine_y[m] += maybe;
    }

    maybe = random(2);
    if (machine_x[m] > human_x) {
        machine_x[m] -= maybe;
    } else if (machine_x[m] < human_x) {
        machine_x[m] += maybe;
    }

    if (arena[machine_y[m]][machine_x[m]] == EMPTY) {
        arena[machine_y[m]][machine_x[m]] = MACHINE;
    } else if (arena[machine_y[m]][machine_x[m]] == FENCE) {
        operative[m] = false;
        destroyed_machines += 1;
        if (destroyed_machines == MACHINES) {
            the_end = VICTORY;
        }
    } else if (arena[machine_y[m]][machine_x[m]] == HUMAN) {
        the_end = KILLED;
    }

}

void maybe_move_machine(int m) {
    if (random(MACHINES_DRAG) == 0) {
        move_machine(m);
    }
}

void move_machines() {
    for (int m = 0; m < MACHINES; m += 1) {
        if (operative[m]) {
            maybe_move_machine(m);
        }
    }
}

// Read a user command; update `the_end` accordingly and return the direction
// increments.
//
array(int) get_move() {
    int y_inc = 0;
    int x_inc = 0;
    write("\n");
    erase_line_to_end();
    string command = lower_case(get_string("Command: "));
    switch (command) {
        case "q":
            the_end = QUIT;
            break;
        case "sw":
            y_inc = 1;
            x_inc = -1;
            break;
        case "s":
            y_inc = 1;
            break;
        case "se":
            y_inc = 1;
            x_inc = 1;
            break;
        case "w":
            x_inc = -1;
            break;
        case "e":
            x_inc = 1;
            break;
        case "nw":
            y_inc = -1;
            x_inc = -1;
            break;
        case "n":
            y_inc = -1;
            break;
        case "ne":
            y_inc = -1;
            x_inc = 1;

    }
    return ({y_inc, x_inc});
}

void play() {

    int y_inc = 0;
    int x_inc = 0;

    while (true) { // game loop

        clear_screen();
        print_title();
        init_game();

        while (true) { // action loop
            print_arena();
            array(int) coords = get_move();
            y_inc = coords[0];
            x_inc = coords[1];
            if (the_end == NOT_YET) {
                if (y_inc != 0 || x_inc != 0) {
                    arena[human_y][human_x] = EMPTY;
                    if (arena[human_y + y_inc][human_x + x_inc] == FENCE) {
                        the_end = ELECTRIFIED;
                    } else if (arena[human_y + y_inc][human_x + x_inc] == MACHINE) {
                        the_end = KILLED;
                    } else {
                        arena[human_y][human_x] = EMPTY;
                        human_y = human_y + y_inc;
                        human_x = human_x + x_inc;
                        arena[human_y][human_x] = HUMAN;
                        print_arena();
                        move_machines();
                    }
                }
            }
            if (the_end != NOT_YET) {
                break;
            }
        } // action loop;

        switch (the_end) {
            case QUIT:
                write("\nSorry to see you quit.\n");
                break;
            case ELECTRIFIED:
                write("\nZap! You touched the fence!\n");
                break;
            case KILLED:
                write("\nYou have been killed by a lucky machine.\n");
                break;
            case VICTORY:
                write("\nYou are lucky, you destroyed all machines.\n");

        }

        if (!yes("\nDo you want to play again? ")) {
            break;
        }
    } // game loop

    write("\nHope you don't feel fenced in.\n");
    write("Try again sometime.\n");
}

// Main {{{1
// =============================================================

void main() {
    set_style(DEFAULT_INK);
    clear_screen();
    print_credits();
    press_enter("\nPress the Enter key to read the instructions. ");
    clear_screen();
    print_instructions();
    press_enter("\nPress the Enter key to start. ");
    play();
}

Diamond

#! /usr/bin/env pike

// Diamond

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

// This version in Pike:
//  Copyright (c) 2024, Marcos Cruz (programandala.net)
//  SPDX-License-Identifier: Fair

// Written on 2024-12-17.

// Last modified: 20250310T0308+0100

constant LINES = 17;

void main() {

    for (int i = 1; i <= LINES / 2 + 1; i += 1) {
        for (int j = 1; j <= (LINES + 1) / 2 - i + 1; j += 1)
            write(" ");
        for (int j = 1; j <= i * 2 - 1; j += 1)
            write("*");
        write("\n");
    }

    for (int i = 1; i <= LINES / 2; i += 1) {
        for (int j = 1; j <= i + 1; j += 1)
            write(" ");
        for (int j = 1; j <= ((LINES + 1) / 2 - i) * 2 - 1; j += 1)
            write("*");
        write("\n");
    }

}

Hammurabi

#!/usr/bin/env pike

// Hammurabi

// Description:
//  A simple text-based simulation game set in the ancient kingdom of Sumeria.

// Original program:
//  Written in FOCAL on a DEP PDP-8 by Rick Merrill, 1969.
//
// BASIC port:
//  Ported from FOCAL and modified for Edusystem 70 by David Ahl, c. 1973.
//  Modified for 8K Microsoft BASIC by Peter Turnbull, c. 1978.
//
// More details:
//  - https://en.wikipedia.org/wiki/Hamurabi_(video_game)
//  - https://www.mobygames.com/game/22232/hamurabi/

// This improved remake in Pike:
//  Copyright (c) 2025, Marcos Cruz (programandala.net)
//  SPDX-License-Identifier: Fair
//
// Written on 2025-03-11.
//
// Last modified: 20250731T1954+0200.
//
// Acknowledgment:
//  The following Python port was used as a reference of the original
//  variables: <https://github.com/jquast/hamurabi.py>.
//

// Modules {{{1
// =============================================================


// Terminal {{{1
// =============================================================================

constant BLACK = 0;
constant RED = 1;
constant GREEN = 2;
constant YELLOW = 3;
constant BLUE = 4;
constant MAGENTA = 5;
constant CYAN = 6;
constant WHITE = 7;
constant DEFAULT = 9;

constant STYLE_OFF = 20;
constant FOREGROUND = 30;
constant BACKGROUND = 40;
constant BRIGHT = 60;

constant NORMAL_STYLE = 0;

void move_cursor_home() {
    write("\x1B[H");
}

void set_style(int style) {
    write("\x1B[%dm", style);
}

void reset_attributes() {
    set_style(NORMAL_STYLE);
}

void erase_screen() {
    write("\x1B[2J");
}

void clear_screen() {
    erase_screen();
    reset_attributes();
    move_cursor_home();
}

// Data {{{1
// =============================================================

constant ACRES_A_BUSHEL_CAN_SEED = 2; // yearly
constant ACRES_A_PERSON_CAN_SEED = 10; // yearly
constant ACRES_PER_PERSON = 10; // to calculate the initial acres of the city
constant BUSHELS_TO_FEED_A_PERSON = 20; // yearly
constant IRRITATION_LEVELS = 5; // after the switch in `show_irritation`
constant IRRITATION_STEP = MAX_IRRITATION / IRRITATION_LEVELS;
constant MAX_HARVESTED_BUSHELS_PER_ACRE = MIN_HARVESTED_BUSHELS_PER_ACRE + RANGE_OF_HARVESTED_BUSHELS_PER_ACRE - 1;
constant MIN_HARVESTED_BUSHELS_PER_ACRE = 17;
constant MAX_IRRITATION = 16;
constant PLAGUE_CHANCE = 0.15; // 15% yearly
constant RANGE_OF_HARVESTED_BUSHELS_PER_ACRE = 10;
constant YEARS = 10; // goverment period

constant DEFAULT_INK = FOREGROUND + WHITE;
constant INPUT_INK = FOREGROUND + BRIGHT + GREEN;
constant INSTRUCTIONS_INK = FOREGROUND + YELLOW;
constant RESULT_INK = FOREGROUND + BRIGHT + CYAN;
constant SPEECH_INK = FOREGROUND + BRIGHT + MAGENTA;
constant TITLE_INK = FOREGROUND + BRIGHT + WHITE;
constant WARNING_INK = FOREGROUND + BRIGHT + RED;

enum Result {
    VERY_GOOD,
    NOT_TOO_BAD,
    BAD,
    VERY_BAD
}

int acres = 0;
int bushels_eaten_by_rats = 0;
int bushels_harvested = 0;
int bushels_harvested_per_acre = 0;
int bushels_in_store = 0;
int bushels_to_feed_with = 0;
int dead = 0;
int infants = 0;
int irritation = 0; // counter (0 ..= 99)
int population = 0;
int starved_people_percentage = 0;
int total_dead = 0;

// Credits and instructions {{{1
// =============================================================

constant CREDITS =
"Hammurabi\n" +
"\n" +
"Original program:\n" +
"  Written in FOCAL on a DEP PDP-8 by Rick Merrill, 1969.\n" +
"\n" +
"BASIC port:\n" +
"  Ported from FOCAL and modified for Edusystem 70 by David Ahl, c. 1973.\n" +
"  Modified for 8K Microsoft BASIC by Peter Turnbull, c. 1978.\n" +
"\n" +
"This improved remake in Pike:\n" +
"  Copyright (c) 2025, Marcos Cruz (programandala.net)\n" +
"  SPDX-License-Identifier: Fair\n";

void print_credits() {
    set_style(TITLE_INK);
    write("%s\t", CREDITS);
    set_style(DEFAULT_INK);
}

constant INSTRUCTIONS =
"Hammurabi is a simulation game in which you, as the ruler of the ancient\n" +
"kingdom of Sumeria, Hammurabi, manage the resources.\n" +
"\n" +
"You may buy and sell land with your neighboring city-states for bushels of\n" +
"grain ― the price will vary between %d and %d bushels per acre.  You also must\n" +
"use grain to feed your people and as seed to plant the next year's crop.\n" +
"\n" +
"You will quickly find that a certain number of people can only tend a certain\n" +
"amount of land and that people starve if they are not fed enough.  You also\n" +
"have the unexpected to contend with such as a plague, rats destroying stored\n" +
"grain, and variable harvests.\n" +
"\n" +
"You will also find that managing just the few resources in this game is not a\n" +
"trivial job.  The crisis of population density rears its head very rapidly.\n" +
"\n" +
"Try your hand at governing ancient Sumeria for a %d-year term of office.\n";

void print_instructions() {
    set_style(INSTRUCTIONS_INK);
    write(
        INSTRUCTIONS,
        MIN_HARVESTED_BUSHELS_PER_ACRE,
        MAX_HARVESTED_BUSHELS_PER_ACRE,
        YEARS
        );
    set_style(DEFAULT_INK);
}

// User input {{{1
// =============================================================

string accept_string(string prompt) {
    write(prompt);
    return Stdio.stdin->gets();
}

void pause(void|string prompt ) {
    prompt = prompt || "> ";
    set_style(INPUT_INK);
    accept_string(prompt);
    set_style(DEFAULT_INK);
}

// Print the given prompt, accept a string from the user. If the whole typed
// string is a valid integer (excluding trailing and leading white spaces,
// i.e.: space, tab, newline, carriage return, form feed, vertical tab and all
// the white spaces defined in Unicode), then return the number; otherwise
// return the typed string.
//
int|string accept_integer(string prompt) {
    string s = String.trim(accept_string(prompt));
    int n = (int) s;
    if ((string) n == s) {
        return n;
    } else {
        return s;
    }
}

// Print the given prompt, accept a string from the user. If the whole typed
// string is a valid integer (excluding trailing and leading white spaces,
// i.e.: space, tab, newline, carriage return, form feed, vertical tab and all
// the white spaces defined in Unicode), then return the number; otherwise
// return -1.
//
int get_integer(string prompt) {
    set_style(INPUT_INK);
    int|string answer = accept_integer(prompt);
    set_style(DEFAULT_INK);
    if (stringp(answer)) {
        return -1;
    } else {
        return answer;
    }
}

// Random numbers {{{1
// =============================================================

// Return a random number from 1 to 5 (inclusive).
//
int random_1_to_5() {
    return random(5) + 1;
}

// Strings {{{1
// =============================================================

// Return a string with the proper wording for `n` persons, using the given or
// default words for singular and plural forms.
//
string persons(int n, string|void singular, string|void plural) {

    singular = singular || "person";
    plural = plural || "people";

    switch (n) {
        case 0: return "nobody";
        case 1: return sprintf("one %s", singular);
        default: return sprintf("%d %s", n, plural);
    }

}

string ordinal_suffix(int n) {
    switch (n) {
    case 1: return "st";
    case 2: return "nd";
    case 3: return "rd";
    default: return "th";
    }
}

// Game {{{1
// =============================================================================

// Return a string with the description of the given year as the previous one.
//
string previous(int year) {
    if (year == 0) {
        return "the previous year";
    } else {
        return sprintf("your %d%s year", year, ordinal_suffix(year));
    }
}

void print_annual_report(int year) {
    clear_screen();
    set_style(SPEECH_INK);
    write("Hammurabi, I beg to report to you.\n");
    set_style(DEFAULT_INK);

    string year_text = previous(year);
    string persons_text = persons(dead);
    string infants_text = persons(infants);

    write(
        "\nIn %s, %s starved and %s %s born.\n",
        year_text,
        persons_text,
        infants_text,
        (infants > 1) ? "were" : "was"
    );

    population += infants;

    if (year > 0 && random(1.0) <= PLAGUE_CHANCE) {
        population = (int) (population / 2);
        set_style(WARNING_INK);
        write("A horrible plague struck!  Half the people died.\n");
        set_style(DEFAULT_INK);
    }

    write("The population is %d.\n", population);
    write("The city owns %d acres.\n", acres);
    write(
        "You harvested %d bushels (%d per acre).\n",
        bushels_harvested,
        bushels_harvested_per_acre
    );
    if (bushels_eaten_by_rats > 0) {
        write("The rats ate %d bushels.\n", bushels_eaten_by_rats);
    }
    write("You have %d bushels in store.\n", bushels_in_store);
    bushels_harvested_per_acre =
        (int) ((float) RANGE_OF_HARVESTED_BUSHELS_PER_ACRE * random(1.0)) +
        MIN_HARVESTED_BUSHELS_PER_ACRE;
    write("Land is trading at %d bushels per acre.\n\n", bushels_harvested_per_acre);
}

void say_bye() {
    set_style(DEFAULT_INK);
    write("\nSo long for now.\n\n");
}

void quit_game() {
    say_bye();
    exit(0);
}

void relinquish() {
    set_style(SPEECH_INK);
    write("\nHammurabi, I am deeply irritated and cannot serve you anymore.\n");
    write("Please, get yourself another steward!\n");
    set_style(DEFAULT_INK);
    quit_game();
}

void increase_irritation() {
    irritation += 1 + random(IRRITATION_STEP);
    if (irritation >= MAX_IRRITATION) {
        relinquish(); // this never returns
    }
}

void print_irritated(string adverb) {
    write("The steward seems %s irritated.\n", adverb);
}

void show_irritation() {
    if (irritation < IRRITATION_STEP * 2) {
        print_irritated("slightly");
    } else if (irritation < IRRITATION_STEP * 3) {
        print_irritated("quite");
    } else if (irritation < IRRITATION_STEP * 4) {
        print_irritated("very");
    } else {
        print_irritated("profoundly");
    }
}

// Print a message begging to repeat an ununderstandable input.
//
void beg_repeat() {
    increase_irritation(); // this may never return
    set_style(SPEECH_INK);
    write("I beg your pardon?  I did not understand your order.\n");
    set_style(DEFAULT_INK);
    show_irritation();
}

// Print a message begging to repeat a wrong input, because there's only `n`
// items of `name`.
//
void beg_think_again(int n, string name) {
    increase_irritation(); // this may never return
    set_style(SPEECH_INK);
    write("I beg your pardon?  You have only %d %s.  Now then…\n", n, name);
    set_style(DEFAULT_INK);
    show_irritation();
}

// Buy or sell land.
//
void trade() {

    int acres_to_buy = 0;
    int acres_to_sell = 0;

    while (true) {
        acres_to_buy = get_integer("How many acres do you wish to buy? (0 to sell): ");
        if (acres_to_buy < 0) {
            beg_repeat(); // this may never return
        } else {
            if (bushels_harvested_per_acre * acres_to_buy <= bushels_in_store) {
                break;
            } else {
                beg_think_again(bushels_in_store, "bushels of grain");
            }
        }
    }

    if (acres_to_buy != 0) {
        write("You buy %d acres.\n", acres_to_buy);
        acres += acres_to_buy;
        bushels_in_store -= bushels_harvested_per_acre * acres_to_buy;
        write("You now have %d acres and %d bushels.\n", acres, bushels_in_store);
    } else {
        while (true) {
            acres_to_sell = get_integer("How many acres do you wish to sell?: ");
            if (acres_to_sell < 0) {
                beg_repeat(); // this may never return
            } else {
                if (acres_to_sell < acres) {
                    break;
                } else {
                    beg_think_again(acres, "acres");
                }
            }
        }

        if (acres_to_sell > 0) {
            write("You sell %d acres.\n", acres_to_sell);
            acres -= acres_to_sell;
            bushels_in_store += bushels_harvested_per_acre * acres_to_sell;
            write("You now have %d acres and %d bushels.\n", acres, bushels_in_store);
        }
    }
}

// Feed the people.
//
void feed() {
    while (true) {
        bushels_to_feed_with = get_integer("How many bushels do you wish to feed your people with?: ");
        if (bushels_to_feed_with < 0) {
            beg_repeat(); // this may never return
        } else {
            // Trying to use more grain than is in silos?
            if (bushels_to_feed_with <= bushels_in_store) {
                break;
            } else {
                beg_think_again(bushels_in_store, "bushels of grain");
            }
        }
    }

    write("You feed your people with %d bushels.\n", bushels_to_feed_with);
    bushels_in_store -= bushels_to_feed_with;
    write("You now have %d bushels.\n", bushels_in_store);
}

// Seed the land.
//
void seed() {

    int acres_to_seed = 0;

    while (true) {
        acres_to_seed = get_integer("How many acres do you wish to seed?: ");
        if (acres_to_seed < 0) {
            beg_repeat(); // this may never return
            continue;
        }
        if (acres_to_seed == 0) {
            break;
        }

        // Trying to seed more acres than you own?
        if (acres_to_seed > acres) {
            beg_think_again(acres, "acres");
            continue;
        }

        string message = sprintf(
            "bushels of grain,\nand one bushel can seed %d acres",
            ACRES_A_BUSHEL_CAN_SEED
        );

        // Enough grain for seed?
        if ((int) (acres_to_seed / ACRES_A_BUSHEL_CAN_SEED) > bushels_in_store) {
            beg_think_again(bushels_in_store, message);
            continue;
        }

        // Enough people to tend the crops?
        if (acres_to_seed <= ACRES_A_PERSON_CAN_SEED * population) {
            break;
        }

        message = sprintf(
            "people to tend the fields,\nand one person can seed %d acres",
            ACRES_A_PERSON_CAN_SEED
        );

        beg_think_again(population, message);
    }

    int bushels_used_for_seeding = (acres_to_seed / ACRES_A_BUSHEL_CAN_SEED);
    write("You seed %d acres using %d bushels.\n", acres_to_seed, bushels_used_for_seeding);
    bushels_in_store -= bushels_used_for_seeding;
    write("You now have %d bushels.\n", bushels_in_store);

    // A bountiful harvest!
    bushels_harvested_per_acre = random_1_to_5();
    bushels_harvested = acres_to_seed * bushels_harvested_per_acre;
    bushels_in_store += bushels_harvested;
}

bool is_even(int n) {
    return n % 2 == 0;
}

void check_rats() {
    int rat_chance = random_1_to_5();
    bushels_eaten_by_rats = is_even(rat_chance) ? (int) (bushels_in_store / rat_chance) : 0;
    bushels_in_store -= bushels_eaten_by_rats;
}

// Set the variables to their values in the first year.
//
void init() {
    dead = 0;
    total_dead = 0;
    starved_people_percentage = 0;
    population = 95;
    infants = 5;
    acres = ACRES_PER_PERSON * (population + infants);
    bushels_harvested_per_acre = 3;
    bushels_harvested = acres * bushels_harvested_per_acre;
    bushels_eaten_by_rats = 200;
    bushels_in_store = bushels_harvested - bushels_eaten_by_rats;
    irritation = 0;
}

void print_result(Result r) {
    set_style(RESULT_INK);

    switch (r) {
        case VERY_GOOD:
            write("A fantastic performance!  Charlemagne, Disraeli and Jefferson combined could\n");
            write("not have done better!\n");
            break;
        case NOT_TOO_BAD:
            write("Your performance could have been somewat better, but really wasn't too bad at\n");
            write(
                "all. %d people would dearly like to see you assassinated, but we all have our\n",
                (int) (population * 0.8 * random(1.0))
            );
            write("trivial problems.\n");
            break;
        case BAD:
            write("Your heavy-handed performance smacks of Nero and Ivan IV.  The people\n");
            write("(remaining) find you an unpleasant ruler and, frankly, hate your guts!\n");
            break;
        case VERY_BAD:
            write("Due to this extreme mismanagement you have not only been impeached and thrown\n");
            write("out of office but you have also been declared national fink!!!\n");
    }

    set_style(DEFAULT_INK);
}

void print_final_report() {
    clear_screen();

    if (starved_people_percentage > 0) {
        write(
            "In your %d-year term of office, %d percent of the\n",
            YEARS,
            starved_people_percentage
        );
        write(
            "population starved per year on the average, i.e., a total of %d people died!\n\n",
            total_dead
        );
    }

    int acres_per_person = acres / population;
    write(
        "You started with %d acres per person and ended with %d.\n\n",
        ACRES_PER_PERSON,
        acres_per_person
    );

    if (starved_people_percentage > 33 || acres_per_person < 7) {
        print_result(VERY_BAD);
    } else if (starved_people_percentage > 10 || acres_per_person < 9) {
        print_result(BAD);
    } else if (starved_people_percentage > 3 || acres_per_person < 10) {
        print_result(NOT_TOO_BAD);
    } else {
        print_result(VERY_GOOD);
    }
}

void check_starvation(int year) {
    // How many people has been fed?
    int fed_people = (bushels_to_feed_with / BUSHELS_TO_FEED_A_PERSON);

    if (population > fed_people) {
        dead = population - fed_people;
        starved_people_percentage = ((year - 1) * starved_people_percentage + dead * 100 / population) / year;
        population -= dead;
        total_dead += dead;

        // Starve enough for impeachment?
        if (dead > (int) (0.45 * population)) {
            set_style(WARNING_INK);
            write("\nYou starved %d people in one year!!!\n\n", dead);
            set_style(DEFAULT_INK);
            print_result(VERY_BAD);
            quit_game();
        }
    }
}

void govern() {
    init();

    print_annual_report(0);

    for (int year = 1; year <= YEARS; year += 1) {
        trade();
        feed();
        seed();
        check_rats();

        // Let's have some babies
        infants = (int) (random_1_to_5() * (20 * acres + bushels_in_store) / population / 100 + 1);

        check_starvation(year);

        pause("\nPress the Enter key to read the annual report. ");
        print_annual_report(year);
    }
}

// Main {{{1
// =============================================================

void main() {
    clear_screen();
    print_credits();
    pause("\nPress the Enter key to read the instructions. ");
    clear_screen();
    print_instructions();
    pause("\nPress the Enter key to start. ");
    govern();
    pause("Press the Enter key to read the final report. ");
    print_final_report();
    say_bye();
}

High Noon

#!/usr/bin/env pike

// High Noon

// Original version in BASIC:
//  Designed and programmed by Chris Gaylo, Syosset High School, New York, 1970-09-12.
//  http://mybitbox.com/highnoon-1970/
//  http://mybitbox.com/highnoon/

// Transcriptions:
//  https://github.com/MrMethor/Highnoon-BASIC/
//  https://github.com/mad4j/basic-highnoon/

// Version modified for QB64:
//  By Daniele Olmisani, 2014.
//  https://github.com/mad4j/basic-highnoon/

// This improved remake in Pike:
//  Copyright (c) 2025, Marcos Cruz (programandala.net)
//  SPDX-License-Identifier: Fair
//
// Written on 2025-03-10.
//
// Last modified: 20250323T2314+0100.

// Terminal {{{1
// =============================================================================

constant BLACK = 0;
constant RED = 1;
constant GREEN = 2;
constant YELLOW = 3;
constant BLUE = 4;
constant MAGENTA = 5;
constant CYAN = 6;
constant WHITE = 7;
constant DEFAULT = 9;

constant STYLE_OFF = 20;
constant FOREGROUND = 30;
constant BACKGROUND = 40;
constant BRIGHT = 60;

constant NORMAL_STYLE = 0;

void move_cursor_home() {
    write("\x1B[H");
}

void hide_cursor() {
    write("\x1B[?25l");
}

void show_cursor() {
    write("\x1B[?25h");
}

void set_style(int style) {
    write("\x1B[%dm", style);
}

void reset_attributes() {
    set_style(NORMAL_STYLE);
}

void erase_screen() {
    write("\x1B[2J");
}

void clear_screen() {
    erase_screen();
    reset_attributes();
    move_cursor_home();
}

// Global variables and constants {{{1
// =============================================================

constant DEFAULT_INK = FOREGROUND + WHITE;
constant INPUT_INK = FOREGROUND + BRIGHT + GREEN;
constant INSTRUCTIONS_INK = FOREGROUND + YELLOW;
constant TITLE_INK = FOREGROUND + BRIGHT + RED;

constant INITIAL_DISTANCE = 100;
constant INITIAL_BULLETS = 4;
constant MAX_WATERING_TROUGHS = 3;

int distance = 0; // distance between both gunners, in paces

int player_bullets = 0;
int opponent_bullets = 0;

// User input {{{1
// =============================================================================

string accept_string(string prompt) {
    write(prompt);
    return Stdio.stdin->gets();
}

// Print the given prompt and wait until the user enters a string.
//
string get_string(string prompt) {
    set_style(INPUT_INK);
    string s = accept_string(prompt);
    set_style(DEFAULT_INK);
    return s;
}

int accept_integer(string prompt) {
    // NB The casting accepts any valid integer at the start of the string
    // and ignores the rest;  if no valid integer is found at the start of
    // the string, zero is returned.
    return (int) accept_string(prompt);
}

// Print the given prompt and wait until the user enters an integer.
//
int get_integer(string prompt) {
    set_style(INPUT_INK);
    int n = accept_integer(prompt);
    set_style(DEFAULT_INK);
    return n;
}

// Return `true` if the given string is "yes" or a synonym.
//
bool is_yes(string s) {
    switch(lower_case(s)) {
        case "ok":
        case "y":
        case "yeah":
        case "yes":
            return true;
        default:
            return false;
    }
}

// Return `true` if the given string is "no" or a synonym.
//
bool is_no(string s) {
    switch(lower_case(s)) {
        case "n":
        case "no":
        case "nope":
            return true;
        default:
            return false;
    }
}

// Print the given prompt, wait until the user enters a valid yes/no string,
// and return `true` for "yes" or `false` for "no".
//
bool yes(string prompt) {
    while (true) {
        string answer = get_string(prompt);
        if (is_yes(answer)) {
            return true;
        }
        if (is_no(answer)) {
            return false;
        }
    }
}

// Title, instructions and credits {{{1
// =============================================================

void print_title() {
    set_style(TITLE_INK);
    write("High Noon\n");
    set_style(DEFAULT_INK);
}

void print_credits() {
    print_title();
    write("\nOriginal version in BASIC:\n");
    write("    Designed and programmend by Chris Gaylo, 1970.\n");
    write("    http://mybitbox.com/highnoon-1970/\n");
    write("    http://mybitbox.com/highnoon/\n");
    write("Transcriptions:\n");
    write("    https://github.com/MrMethor/Highnoon-BASIC/\n");
    write("    https://github.com/mad4j/basic-highnoon/\n");
    write("Version modified for QB64:\n");
    write("    By Daniele Olmisani, 2014.\n");
    write("    https://github.com/mad4j/basic-highnoon/\n");
    write("This improved remake in Pike:\n");
    write("    Copyright (c) 2025, Marcos Cruz (programandala.net)\n");
    write("    SPDX-License-Identifier: Fair\n");
}

void print_instructions() {
    print_title();
    set_style(INSTRUCTIONS_INK);
    write("\nYou have been challenged to a showdown by Black Bart, one of\n");
    write("the meanest desperadoes west of the Allegheny mountains.\n");
    write("\nWhile you are walking down a dusty, deserted side street,\n");
    write("Black Bart emerges from a saloon one hundred paces away.\n");
    write("\nBy agreement, you each have %d bullets in your six-guns.", INITIAL_BULLETS);
    write("\nYour marksmanship equals his. At the start of the walk nei-\n");
    write("ther of you can possibly hit the other, and at the end of\n");
    write("the walk, neither can miss. the closer you get, the better\n");
    write("your chances of hitting black Bart, but he also has beter\n");
    write("chances of hitting you.\n");
    set_style(DEFAULT_INK);
}

// Game loop {{{1
// =============================================================

string plural_suffix(int n) {
    switch (n) {
        case 1: return "";
        default: return "s";
    }
}

void print_shells_left() {
    if (player_bullets == opponent_bullets) {
        write("Both of you have %d bullets.\n", player_bullets);
    } else {
        write(
            "You now have %d bullet%s to Black Bart's %d bullet%s.\n",
            player_bullets,
            plural_suffix(player_bullets),
            opponent_bullets,
            plural_suffix(opponent_bullets));
    }
}

void print_check() {
    write("******************************************************\n");
    write("*                                                    *\n");
    write("*                 BANK OF DODGE CITY                 *\n");
    write("*                  CASHIER'S RECEIT                  *\n");
    write("*                                                    *\n");
    write("* CHECK NO. %04d                   AUGUST %dTH, 1889 *\n",
        random(1000),
        10 + random(10));
    write("*                                                    *\n");
    write("*                                                    *\n");
    write("*       PAY TO THE BEARER ON DEMAND THE SUM OF       *\n");
    write("*                                                    *\n");
    write("* TWENTY THOUSAND DOLLARS-------------------$20,000  *\n");
    write("*                                                    *\n");
    write("******************************************************\n");
}

void get_reward() {
    write("As mayor of Dodge City, and on behalf of its citizens,\n");
    write("I extend to you our thanks, and present you with this\n");
    write("reward, a check for $20,000, for killing Black Bart.\n\n\n");
    print_check();
    write("\n\nDon't spend it all in one place.\n");
}

void move_the_opponent() {
    int paces = 2 + random(8);
    write("Black Bart moves %d paces.\n", paces);
    distance -= paces;
}

// Maybe move the opponent; if so, return `true`, otherwise return `false`. A
// true `silent` flag allows to omit the message when the opponent doesn't
// move.
//
bool maybe_move_the_opponent(bool silent) {
    if (random(2) == 0) { // 50% chances
        move_the_opponent();
        return true;
    } else {
        if (!silent) {
            write("Black Bart stands still.\n");
        }
        return false;
    }
}

bool missed_shot() {
    return random(1.0) * 10.0 <= (distance / 10);
}

// Handle the opponent's shot and return a flag with the result: if the
// opponent kills the player, return `true`; otherwise return `false`.
//
bool the_opponent_fires_and_kills(string player_strategy) {
    write("Black Bart fires…\n");
    opponent_bullets -= 1;
    if (missed_shot()) {
        write("A miss…\n");
        switch (opponent_bullets) {
            case 3:
                write("Whew, were you lucky. That bullet just missed your head.\n");
                break;
            case 2:
                write("But Black Bart got you in the right shin.\n");
                break;
            case 1:
                write("Though Black Bart got you on the left side of your jaw.\n");
                break;
            case 0:
                write("Black Bart must have jerked the trigger.\n");
        }
    } else {
        if (player_strategy == "j") {
            write("That trick just saved yout life. Black Bart's bullet\n");
            write("was stopped by the wood sides of the trough.\n");
        } else {
            write("Black Bart shot you right through the heart that time.\n");
            write("You went kickin' with your boots on.\n");
            return true;
        }
    }
    return false;
}

// Handle the opponent's strategy and return a flag with the result: if the
// opponent runs or kills the player, return `true`; otherwise return `false`.
//
bool the_opponent_kills_or_runs(string player_strategy) {
    if (distance >= 10 || player_bullets == 0) {
        if (maybe_move_the_opponent(true)) {
            return false;
        }
    }
    if (opponent_bullets > 0) {
        return the_opponent_fires_and_kills(player_strategy);
    } else {
        if (player_bullets > 0) {
            if (random(2) == 0) { // 50% chances
                write("Now is your chance, Black Bart is out of bullets.\n");
            } else {
                write("Black Bart just hi-tailed it out of town rather than face you\n");
                write("without a loaded gun. You can rest assured that Black Bart\n");
                write("won't ever show his face around this town again.\n");
                return true;
            }
        }
    }
    return false;
}

void play() {

    distance = INITIAL_DISTANCE;
    int watering_troughs = 0;
    player_bullets = INITIAL_BULLETS;
    opponent_bullets = INITIAL_BULLETS;

    showdown: while (true) {

        write("You are now %d paces apart from Black Bart.\n", distance);
        print_shells_left();
        set_style(INSTRUCTIONS_INK);
        write("\nStrategies:\n");
        write("  [A]dvance\n");
        write("  [S]tand still\n");
        write("  [F]ire\n");
        write("  [J]ump behind the watering trough\n");
        write("  [G]ive up\n");
        write("  [T]urn tail and run\n");
        set_style(DEFAULT_INK);

        string player_strategy = lower_case(get_string("What is your strategy? "));

        switch (player_strategy) {

            case "a": // advance

                while (true) {
                    int paces = get_integer("How many paces do you advance? ");
                    if (paces < 0) {
                        write("None of this negative stuff, partner, only positive numbers.\n");
                    } else if (paces > 10) {
                        write("Nobody can walk that fast.\n");
                    } else {
                        distance -= paces;
                        break;
                    }
                }
                break;

            case "s": // stand still

                write("That move made you a perfect stationary target.\n");
                break;

            case "f": // fire

                if (player_bullets == 0) {

                    write("You don't have any bullets left.\n");

                } else {

                    player_bullets -= 1;
                    if (missed_shot()) {
                        switch (player_bullets) {
                            case 2:
                                write("Grazed Black Bart in the right arm.\n");
                                break;
                            case 1:
                                write("He's hit in the left shoulder, forcing him to use his right\n");
                                write("hand to shoot with.\n");
                        }
                        write("What a lousy shot.\n");
                        if (player_bullets == 0) {
                            write("Nice going, ace, you've run out of bullets.\n");
                            if (opponent_bullets != 0) {
                                write("Now Black Bart won't shoot until you touch noses.\n");
                                write("You better think of something fast (like run).\n");
                            }
                        }
                    } else {
                        write("What a shot, you got Black Bart right between the eyes.\n");
                        accept_string("\nPress the Enter key to get your reward. ");
                        clear_screen();
                        get_reward();
                        break showdown;
                    }

                }
                break;

            case "j": // jump

                if (watering_troughs == MAX_WATERING_TROUGHS) {
                    write("How many watering troughs do you think are on this street?\n");
                    player_strategy = "";
                } else {
                    watering_troughs += 1;
                    write("You jump behind the watering trough.\n");
                    write("Not a bad maneuver to threw Black Bart's strategy off.\n");
                }
                break;

            case "g": // give up

                write("Black Bart accepts. The conditions are that he won't shoot you\n");
                write("if you take the first stage out of town and never come back.\n");
                if (yes("Agreed? ")) {
                    write("A very wise decision.\n");
                    break showdown;
                } else {
                    write("Oh well, back to the showdown.\n");
                }
                break;

            case "t": // turn tail and run

                // The more bullets of the opponent, the less chances to escape.
                if (random((opponent_bullets + 2)) == 0) {
                    write("Man, you ran so fast even dogs couldn't catch you.\n");
                } else {
                    switch (opponent_bullets) {
                        case 0:
                            write("You were lucky, Black Bart can only throw his gun at you, he\n");
                            write("doesn't have any bullets left. You should really be dead.\n");
                            break;
                        case 1:
                            write("Black Bart fires his last bullet…\n");
                            write("He got you right in the back. That's what you deserve, for running.\n");
                            break;
                        case 2:
                            write("Black Bart fires and got you twice: in your back\n");
                            write("and your ass. Now you can't even rest in peace.\n");
                            break;
                        case 3:
                            write("Black Bart unloads his gun, once in your back\n");
                            write("and twice in your ass. Now you can't even rest in peace.\n");
                            break;
                        case 4:
                            write("Black Bart unloads his gun, once in your back\n");
                            write("and three times in your ass. Now you can't even rest in peace.\n");
                    }
                    opponent_bullets = 0;
                }
                break showdown;

            default:

                write("You sure aren't going to live very long if you can't even follow directions.\n");

        } // strategy switch

        if (the_opponent_kills_or_runs(player_strategy)) {
            break;
        }

        if (player_bullets + opponent_bullets == 0) {
            write("The showdown must end, because nobody has bullets left.\n");
            break;
        }

        write("\n");

    } // showdown loop

}

// Main {{{1
// =============================================================

void main() {
    clear_screen();
    print_credits();
    accept_string("\nPress the Enter key to read the instructions. ");
    clear_screen();
    print_instructions();
    accept_string("\nPress the Enter key to start. ");
    clear_screen();
    play();
}

Math

#! /usr/bin/env pike

// Math

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

// This version in Pike:
//  Copyright (c) 2025, Marcos Cruz (programandala.net)
//  SPDX-License-Identifier: Fair
//
// Written on 2025-03-09.
//
// Last modified: 20250309T2257+0100.

string accept_string(string prompt) {
    write(prompt);
    return Stdio.stdin->gets();
}

float accept_float(string prompt) {
    // NB The casting accepts any valid float at the start of the string
    // and ignores the rest;  if no valid float is found at the start of
    // the string, zero is returned.
    return (float) accept_string(prompt);
}

float accept_valid_float(string prompt) {
    float n = 0;
    while (n <= 0) {
        n = accept_float(prompt);
        if (n <= 0) {
            write("Float greater than zero expected.\n");
        }
    }
    return n;
}


void main() {

    float n = accept_valid_float("Enter a number: ");

    write("ABS(%[0]f) -> abs(%[0]f) -> %[1]f\n", n, abs(n));
    write("ATN(%[0]f) -> atan(%[0]f) -> %[1]f\n", n, atan(n));
    write("COS(%[0]f) -> cos(%[0]f) -> %[1]f\n", n, cos(n));
    write("EXP(%[0]f) -> exp(%[0]f) -> %[1]f\n", n, exp(n));
    write("INT(%[0]f) -> (int) (%[0]f) -> %[1]d\n", n, (int) n);
    write("LOG(%[0]f) -> log(%[0]f) -> %[1]f\n", n, log(n));
    write("SGN(%[0]f) -> sgn(%[0]f) -> %[1]d\n", n, sgn(n));
    write("SQR(%[0]f) -> sqrt(%[0]f) -> %[1]f\n", n, sqrt(n));
    write("TAN(%[0]f) -> tan(%[0]f) -> %[1]f\n", n, tan(n));

}

Mugwump

#!/usr/bin/env pike

// Mugwump

// Original version in BASIC:
//  Written by Bud Valenti's students of Project SOLO (Pittsburg, Pennsylvania, USA).
//  Slightly modified by Bob Albrecht of People's Computer Company.
//  Published by Creative Computing (Morristown, New Jersey, USA), 1978.
//  - https://www.atariarchives.org/basicgames/showpage.php?page=114
//  - http://vintage-basic.net/games.html

// This version in Pike:
//  Copyright (c) 2025, Marcos Cruz (programandala.net)
//  SPDX-License-Identifier: Fair
//
// Written in 2025-03-11/12.
//
// Last modified: 20250731T1954+0200.

// Terminal {{{1
// =============================================================================

constant NORMAL_STYLE = 0;

void move_cursor_home() {
    write("\x1B[H");
}

void set_style(int style) {
    write("\x1B[%dm", style);
}

void reset_attributes() {
    set_style(NORMAL_STYLE);
}

void erase_screen() {
    write("\x1B[2J");
}

void clear_screen() {
    erase_screen();
    reset_attributes();
    move_cursor_home();
}

// Data {{{1
// =============================================================================

constant GRID_SIZE = 10;
constant TURNS = 10;
constant MUGWUMPS = 4;

class Mugwump {
    int x;
    int y;
    bool hidden;
}

array(Mugwump) mugwump = allocate(MUGWUMPS);
int found = 0; // counter

// User input {{{1
// =============================================================================

string accept_string(string prompt) {
    write(prompt);
    return Stdio.stdin->gets();
}

// Print the given prompt, accept a string from the user. If the whole typed
// string is a valid integer (excluding trailing and leading white spaces,
// i.e.: space, tab, newline, carriage return, form feed, vertical tab and all
// the white spaces defined in Unicode), then return the number; otherwise
// return the typed string.
//
int|string accept_integer(string prompt) {
    string s = String.trim(accept_string(prompt));
    int n = (int) s;
    if ((string) n == s) {
        return n;
    } else {
        return s;
    }
}

int prompted_valid_integer(string prompt) {
    while (true) {
        int|string answer = accept_integer(prompt);
        if (stringp(answer)) {
            write("Integer expected.\n");
        } else {
            return answer;
        }
    }
}

bool is_yes(string s) {
    switch(lower_case(s)) {
        case "ok":
        case "y":
        case "yeah":
        case "yes":
            return true;
        default:
            return false;
    }
}

bool is_no(string s) {
    switch(lower_case(s)) {
        case "n":
        case "no":
        case "nope":
            return true;
        default:
            return false;
    }
}

// Print the given prompt, wait until the user enters a valid yes/no string;
// and return `true` for "yes" or `false` for "no".
//
bool yes(string prompt) {
    while (true) {
        string answer = accept_string(prompt);
        if (is_yes(answer)) {
            return true;
        }
        if (is_no(answer)) {
            return false;
        }
    }
}

// Credits and instructions {{{1
// =============================================================================

// Clear the screen, print the credits and ask the user to press enter.
//
void print_credits() {
    clear_screen();
    write("Mugwump\n\n");
    write("Original version in BASIC:\n");
    write("    Written by Bud Valenti's students of Project SOLO (Pittsburg, Pennsylvania, USA).\n");
    write("    Slightly modified by Bob Albrecht of People's Computer Company.\n");
    write("    Published by Creative Computing (Morristown, New Jersey, USA), 1978.\n");
    write("    - https://www.atariarchives.org/basicgames/showpage.php?page=114\n");
    write("    - http://vintage-basic.net/games.html\n\n");
    write("This version in Pike:\n");
    write("    Copyright (c) 2025, Marcos Cruz (programandala.net)\n");
    write("    SPDX-License-Identifier: Fair\n\n");
    accept_string("Press Enter to read the instructions. ");
}

// Clear the screen, print the instructions and ask the user to press enter.
//
void print_instructions() {
    clear_screen();
    write("Mugwump\n\n");
    write("The object of this game is to find four mugwumps\n");
    write("hidden on a 10 by 10 grid.  Homebase is position 0,0.\n");
    write("Any guess you make must be two numbers with each\n");
    write("number between 0 and 9, inclusive.  First number\n");
    write("is distance to right of homebase and second number\n");
    write("is distance above homebase.\n\n");
    write("You get %d tries.  After each try, you will see\n", TURNS);
    write("how far you are from each mugwump.\n\n");
    accept_string("Press Enter to start. ");
}

// Game {{{1
// =============================================================================

void hide_mugwumps() {
    for (int m = 0; m < MUGWUMPS; m += 1) {
        mugwump[m]->x = random(GRID_SIZE);
        mugwump[m]->y = random(GRID_SIZE);
        mugwump[m]->hidden = true;
    }
    found = 0; // counter
}

// Print the given prompt, wait until the user enters a valid coord and return
// it.
//
int get_coord(string prompt) {
    int coord = 0;
    while (true) {
        coord = prompted_valid_integer(prompt);
        if (coord < 0 || coord >= GRID_SIZE) {
            write("Invalid value %d: not in range [0, %d].\n", coord, GRID_SIZE - 1);
        } else {
            break;
        }
    }
    return coord;
}

// Return `true` if the given mugwump is hidden in the given coords.
//
bool is_here(int m, int x, int y) {
    return mugwump[m]->hidden && mugwump[m]->x == x && mugwump[m]->y == y;
}

// Return the distance between the given mugwump and the given coords.
//
int distance(int m, int x, int y) {
    return (int) sqrt(
        pow((mugwump[m]->x - x), 2.0) +
        pow((mugwump[m]->y - y), 2.0));
}

// Return a plural suffix (default: "s") if the given number is greater than 1
// otherwise return a singular suffix (default: an empty string).
//
string plural(int n, string|void plural_suffix, string|void singular_suffix) {
    plural_suffix = plural_suffix || "s";
    singular_suffix = singular_suffix || "";
    return n > 1 ? plural_suffix : singular_suffix;
}

// Run the game.
//
void play() {
    int x = 0;
    int y = 0;
    int turn = 0; // counter

    while (true) { // game

        clear_screen();
        hide_mugwumps();

        turns_loop: for (int turn = 1; turn <= TURNS; turn += 1) {
            write("Turn number %d\n\n", turn);
            write("What is your guess (in range [0, %d])?\n", GRID_SIZE - 1);
            x = get_coord("Distance right of homebase (x-axis): ");
            y = get_coord("Distance above homebase (y-axis): ");
            write("\nYour guess is (%d, %d).\n", x, y);

            for (int m = 0; m < MUGWUMPS; m += 1) {
                if (is_here(m, x, y)) {
                    mugwump[m]->hidden = false;
                    found += 1;
                    write("You have found mugwump %d!\n", m);
                    if (found == MUGWUMPS) {
                        break turns_loop;
                    }
                }
            }

            for (int m = 0; m < MUGWUMPS; m += 1) {
                if (mugwump[m]->hidden) {
                    write("You are %d units from mugwump %d.\n", distance(m, x, y) , m);
                }
            }
            write("\n");
        } // turns

        if (found == MUGWUMPS) {
            write("\nYou got them all in %d turn%s!\n\n", turn, plural(turn));
            write("That was fun! let's play again…\n");
            write("Four more mugwumps are now in hiding.\n");
        } else {
            write("\nSorry, that's %d tr%s.\n\n", TURNS, plural(TURNS, "ies", "y"));
            write("Here is where they're hiding:\n");
            for (int m = 0; m < MUGWUMPS; m += 1) {
                if (mugwump[m]->hidden) {
                    write("Mugwump %d is at (%d, %d).\n", m, mugwump[m]->x, mugwump[m]->y);
                }
            }
        }

        if (!yes("\nDo you want to play again? ")) {
            break;
        }
    } // game
}

// Main {{{1
// =============================================================================

void init() {
    // Build the `mugwump` array.
    for (int i = 0; i < MUGWUMPS; i += 1) {
        mugwump[i] = Mugwump();
    }
}

void main() {
    print_credits();
    print_instructions();
    init();
    play();
}

Name

#! /usr/bin/env pike

// Name

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

// This version in Pike:
//  Copyright (c) 2025, Marcos Cruz (programandala.net)
//  SPDX-License-Identifier: Fair
//
// Written on 2025-03-08.
//
// Last modified: 20250308T1621+0100.

string accept_string(string prompt) {
    write(prompt);
    return Stdio.stdin->gets();
}

int accept_integer(string prompt) {
    // NB The casting accepts any valid integer at the start of the string
    // and ignores the rest;  if no valid integer is found at the start of
    // the string, zero is returned.
    return (int) accept_string(prompt);
}

int accept_valid_integer(string prompt) {
    int n = 0;
    while (n <= 0) {
        n = accept_integer(prompt);
        if (n <= 0) {
            write("Integer greater than zero expected.\n");
        }
    }
    return n;
}

void main() {
    string name = accept_string("What is your name? ");
    int number = accept_valid_integer("Enter a number: ");
    for (int i = 0; i < (number); i += 1) {
        write("Hello, %s!\n", name);
    }
}

Poetry

#! /usr/bin/env pike

// 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 Pike:
//  Copyright (c) 2025, Marcos Cruz (programandala.net)
//  SPDX-License-Identifier: Fair
//
// Written on 2025-03-08.
//
// Last modified: 20250310T0302+0100.

// Terminal {{{1
// =============================================================================

constant BLACK = 0;
constant RED = 1;
constant GREEN = 2;
constant YELLOW = 3;
constant BLUE = 4;
constant MAGENTA = 5;
constant CYAN = 6;
constant WHITE = 7;
constant DEFAULT = 9;

constant STYLE_OFF = 20;
constant FOREGROUND = 30;
constant BACKGROUND = 40;
constant BRIGHT = 60;

constant NORMAL_STYLE = 0;

void move_cursor_home() {
    write("\x1B[H");
}

void set_style(int style) {
    write("\x1B[%dm", style);
}

void reset_attributes() {
    set_style(NORMAL_STYLE);
}

void erase_screen() {
    write("\x1B[2J");
}

void clear_screen() {
    erase_screen();
    reset_attributes();
    move_cursor_home();
}

constant DEFAULT_INK = FOREGROUND + WHITE;
constant INPUT_INK = FOREGROUND + BRIGHT + GREEN;
constant TITLE_INK = FOREGROUND + BRIGHT + RED;

// Title and credits {{{1
// =============================================================================

void print_title() {
    set_style(TITLE_INK);
    write("Poetry\n");
    set_style(DEFAULT_INK);
}

void print_credits() {
    print_title();
    write("\nOriginal version in BASIC:\n");
    write("    Unknown author.\n");
    write("    Published in \"BASIC Computer Games\",\n");
    write("    Creative Computing (Morristown, New Jersey, USA), 1978.\n\n");
    write("This improved remake in Pike:\n");
    write("    Copyright (c) 2025, Marcos Cruz (programandala.net)\n");
    write("    SPDX-License-Identifier: Fair\n");
}

// Main {{{1
// =============================================================================

string accept_string(string prompt) {
    write(prompt);
    return Stdio.stdin->gets();
}

bool is_even(int n) {
    return n % 2 == 0;
}

void play() {

    int MAX_PHRASES_AND_VERSES = 20;

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

    verse: while (true) {

        bool manage_the_verse_continuation = true;
        bool maybe_add_comma = true;

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

        if (manage_the_verse_continuation) {

            sleep(.25);

            if (maybe_add_comma && !(verse_chunks == 0 || random(1.0) > 0.19)) {
                write(",");
                verse_chunks = 2;
            }

            if (random(1.0) > 0.65) {
                write("\n");
                verse_chunks = 0;
            } else {
                write(" ");
                verse_chunks += 1;
            }

        }

        action += 1;
        phrase = random(5);
        phrases_and_verses += 1;

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

    } // verse loop

}

void main() {
    clear_screen();
    print_credits();
    accept_string("\nPress the Enter key to start. ");
    clear_screen();
    play();
}

Russian Roulette

#! /usr/bin/env pike

// Russian Roulette

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

// This version in Pike:
//  Copyright (c) 2025, Marcos Cruz (programandala.net)
//  SPDX-License-Identifier: Fair
//
// Written on 2025-03-10.
//
// Last modified: 20250310T0310+0100.

// Terminal {{{1
// =============================================================================

constant NORMAL_STYLE = 0;

void move_cursor_home() {
    write("\x1B[H");
}

void set_style(int style) {
    write("\x1B[%dm", style);
}

void reset_attributes() {
    set_style(NORMAL_STYLE);
}

void erase_screen() {
    write("\x1B[2J");
}

void clear_screen() {
    erase_screen();
    reset_attributes();
    move_cursor_home();
}

// User input {{{1
// =============================================================================

string accept_string(string prompt) {
    write(prompt);
    return Stdio.stdin->gets();
}

void press_enter_to_start() {
    accept_string("Press Enter to start. ");
}

// Credits and instructions {{{1
// =============================================================================

void print_credits() {
    clear_screen();
    write("Russian Roulette\n\n");
    write("Original version in BASIC:\n");
    write("    Creative Computing (Morristown, New Jersey, USA), ca. 1980.\n\n");
    write("This version in Pike:\n");
    write("    Copyright (c) 2025, Marcos Cruz (programandala.net)\n");
    write("    SPDX-License-Identifier: Fair\n\n");
    press_enter_to_start();
}

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

// Main {{{1
// =============================================================================

void play() {

    int times = 0;

    while (true) { // game loop

        print_instructions();
        times = 0;

        play_loop: while (true) {

            string command = accept_string("> ");

            switch (command) {
                case "f": // fire
                    if (random(100) > 83) {
                        write("Bang! You're dead!\n");
                        write("Condolences will be sent to your relatives.\n");
                        break play_loop;
                    } else {
                        times += 1;
                        if (times > 10) {
                            write("You win!\n");
                            write("Let someone else blow his brains out.\n");
                            break play_loop;
                        } else {
                            write("Click.\n");
                        }
                    }
                    break;
                case "g": // give up
                    write("Chicken!\n");
                    break play_loop;
                case "q": // quit
                    return;
                default:
                    continue;
            }

        } // play loop

        press_enter_to_start();

    } // game loop

}

void bye() {
    write("Bye!\n");
}

void main() {
    print_credits();
    play();
    bye();
}

Seance

#!/usr/bin/env pike

// Seance

// Original version in BASIC:
//  By Chris Oxlade, 1983.
//  https://archive.org/details/seance.qb64
//  https://github.com/chaosotter/basic-games

// This version in Pike:
//  Copyright (c) 2025, Marcos Cruz (programandala.net)
//  SPDX-License-Identifier: Fair
//
// Written on 2025-03-12.
//
// Last modified: 20250731T1954+0200.

// Terminal {{{1
// =============================================================================

constant BLACK = 0;
constant RED = 1;
constant GREEN = 2;
constant YELLOW = 3;
constant BLUE = 4;
constant MAGENTA = 5;
constant CYAN = 6;
constant WHITE = 7;
constant DEFAULT = 9;

constant STYLE_OFF = 20;
constant FOREGROUND = 30;
constant BACKGROUND = 40;
constant BRIGHT = 60;

constant NORMAL_STYLE = 0;

void move_cursor_home() {
    write("\x1B[H");
}

void set_cursor_position(int y, int x) {
    write("\x1B[%d;%dH", y, x);
}

void hide_cursor() {
    write("\x1B[?25l");
}

void show_cursor() {
    write("\x1B[?25h");
}

void set_style(int style) {
    write("\x1B[%dm", style);
}

void reset_attributes() {
    set_style(NORMAL_STYLE);
}

void erase_line_to_end() {
    write("\x1B[K");
}

void erase_screen() {
    write("\x1B[2J");
}

void clear_screen() {
    erase_screen();
    reset_attributes();
    move_cursor_home();
}

// Config {{{1
// =============================================================================

constant TITLE = "Seance";

constant MAX_SCORE = 50;

constant MAX_MESSAGE_LENGTH = 6;
constant MIN_MESSAGE_LENGTH = 3;

constant BASE_CHARACTER = '@';
constant PLANCHETTE = '*';
constant SPACE = ' ';

constant FIRST_LETTER_NUMBER = 1;
constant LAST_LETTER_NUMBER = 26;

constant BOARD_INK = BRIGHT + CYAN + FOREGROUND;
constant DEFAULT_INK = WHITE + FOREGROUND;
constant INPUT_INK = BRIGHT + GREEN + FOREGROUND;
constant INSTRUCTIONS_INK = YELLOW + FOREGROUND;
constant MISTAKE_EFFECT_INK = BRIGHT + RED + FOREGROUND;
constant PLANCHETTE_INK = YELLOW + FOREGROUND;
constant TITLE_INK = BRIGHT + RED + FOREGROUND;

constant BOARD_X = 29; // screen column
constant BOARD_Y = 5; // screen line
constant BOARD_HEIGHT = 5; // characters displayed on the left and right borders
constant BOARD_WIDTH = 8; // characters displayed on the top and bottom borders
constant BOARD_PAD = 1; // blank characters separating the board from its left and right borders

constant BOARD_ACTUAL_WIDTH = BOARD_WIDTH + 2 * BOARD_PAD; // screen columns
constant BOARD_BOTTOM_Y = BOARD_HEIGHT + 1; // relative to the board

constant INPUT_X = BOARD_X;
constant INPUT_Y = BOARD_Y + BOARD_BOTTOM_Y + 4;

constant MESSAGES_Y = INPUT_Y;

constant MISTAKE_EFFECT_PAUSE = 3; // seconds

// User input {{{1
// =============================================================================

string accept_string(string prompt) {
    write(prompt);
    return Stdio.stdin->gets();
}

void press_enter(string prompt) {
    accept_string(prompt);
}

// Credits and instructions {{{1
// =============================================================================

void print_title() {
    set_style(TITLE_INK);
    write("%s\n", TITLE);
    set_style(DEFAULT_INK);
}

void print_credits() {
    print_title();
    write("\nOriginal version in BASIC:\n");
    write("    Written by Chris Oxlade, 1983.\n");
    write("    https://archive.org/details/seance.qb64\n");
    write("    https://github.com/chaosotter/basic-games\n");
    write("This version in Pike:\n");
    write("    Copyright (c) 2025, Marcos Cruz (programandala.net)\n");
    write("    SPDX-License-Identifier: Fair\n");
}

void print_instructions() {
    print_title();
    set_style(INSTRUCTIONS_INK);
    write("\nMessages from the Spirits are coming through, letter by letter.  They want you\n");
    write("to remember the letters and type them into the computer in the correct order.\n");
    write("If you make mistakes, they will be angry -- very angry...\n");
    write("\n");
    write("Watch for stars on your screen -- they show the letters in the Spirits'\n");
    write("messages.\n");
    set_style(DEFAULT_INK);
}

// Game {{{1
// =============================================================================

int random_int_in_inclusive_range(int min, int max) {
    return random((max - min)) + min;
}

// Return the x coordinate to print the given text centered on the board.
//
int board_centered_x(string text) {
    return (BOARD_X + (BOARD_ACTUAL_WIDTH - sizeof(text)) / 2);
}

// Print the given text on the given row, centered on the board.
//
void print_centered(string text, int y) {
    set_cursor_position(y, board_centered_x(text));
    write("%s\n", text);
}

// Print the title on the given row, centered on the board.
//
void print_centered_title(int y) {
    set_style(TITLE_INK);
    print_centered(TITLE, y);
    set_style(DEFAULT_INK);
}

// Print the given letter at the given board coordinates.
//
void print_character(int y, int x, int char) {
    set_cursor_position(y + BOARD_Y, x + BOARD_X);
    write(sprintf("%c", char));
}

void print_board() {
    set_style(BOARD_INK);
    for (int i = 1; i <= BOARD_WIDTH; i += 1) {
        print_character(0, i + 1, BASE_CHARACTER + i); // top border
        print_character(BOARD_BOTTOM_Y, i + 1, BASE_CHARACTER + LAST_LETTER_NUMBER - BOARD_HEIGHT - i + 1); // bottom border
    }
    for (int i = 1; i <= BOARD_HEIGHT; i += 1) {
        print_character(i , 0, BASE_CHARACTER + LAST_LETTER_NUMBER - i + 1); // left border
        print_character(i , 3 + BOARD_WIDTH, BASE_CHARACTER + BOARD_WIDTH + i); // right border
    }
    write("\n");
    set_style(DEFAULT_INK);
}

void erase_line_from(int line, int column) {
    set_cursor_position(line, column);
    erase_line_to_end();
}

// Print the given mistake effect, wait a configured number of seconds and
// finally erase it.
//
void print_mistake_effect(string effect) {
    int x = board_centered_x(effect);
    hide_cursor();
    set_cursor_position(MESSAGES_Y, x);
    set_style(MISTAKE_EFFECT_INK);
    write("%s\n", effect);
    set_style(DEFAULT_INK);
    sleep(MISTAKE_EFFECT_PAUSE);
    erase_line_from(MESSAGES_Y, x);
    show_cursor();
}

// Return a new message of the given length, after marking its letters on the
// board.
//
string message(int length) {
    int y = 0;
    int x = 0;
    string letters = "";
    hide_cursor();
    for (int i = 0; i <= length; i += 1) {
        int letter_number = random_int_in_inclusive_range(
            FIRST_LETTER_NUMBER,
            LAST_LETTER_NUMBER
            );
        letters += sprintf("%c", BASE_CHARACTER + letter_number);
        if (letter_number <= BOARD_WIDTH) {
            // top border
            y = 1;
            x = letter_number + 1;
        } else if (letter_number <= BOARD_WIDTH + BOARD_HEIGHT) {
            // right border
            y = letter_number - BOARD_WIDTH;
            x = 2 + BOARD_WIDTH;
        } else if (letter_number <= BOARD_WIDTH + BOARD_HEIGHT + BOARD_WIDTH) {
            // bottom border
            y = BOARD_BOTTOM_Y - 1;
            x = 2 + BOARD_WIDTH + BOARD_HEIGHT + BOARD_WIDTH - letter_number;
        } else {
            // left border
            y = 1 + LAST_LETTER_NUMBER - letter_number;
            x = 1;
        }
        set_style(PLANCHETTE_INK);
        print_character(y, x, PLANCHETTE);
        set_style(DEFAULT_INK);
        sleep(1);
        print_character(y, x, SPACE);
    }
    show_cursor();
    return letters;

}

string accept_message() {
    set_style(INPUT_INK);
    set_cursor_position(INPUT_Y, INPUT_X);
    string result = upper_case(accept_string("? "));
    set_style(DEFAULT_INK);
    erase_line_from(INPUT_Y, INPUT_X);
    return result;
}

void play() {

    int score = 0;
    int mistakes = 0;

    print_centered_title(1);
    print_board();

    while (true) {
        int message_length = random_int_in_inclusive_range(
            MIN_MESSAGE_LENGTH,
            MAX_MESSAGE_LENGTH
            );
        string message_received = message(message_length);
        string message_understood = accept_message();
        if (message_received != message_understood) {
            mistakes += 1;
            switch (mistakes) {
                case 1:
                    print_mistake_effect("The table begins to shake!");
                    break;
                case 2:
                    print_mistake_effect("The light bulb shatters!");
                    break;
                case 3:
                    print_mistake_effect("Oh, no!  A pair of clammy hands grasps your neck!");
                    return;

            }
        } else {
            score += message_length;
            if (score >= MAX_SCORE) {
                print_centered("Whew!  The spirits have gone!", MESSAGES_Y);
                print_centered("You live to face another day!", MESSAGES_Y + 1);
                return;
            }
        }
    }
}

// Main {{{1
// =============================================================================

void main() {

    set_style(DEFAULT_INK);
    clear_screen();
    print_credits();

    press_enter("\nPress the Enter key to read the instructions. ");
    clear_screen();
    print_instructions();

    press_enter("\nPress the Enter key to start. ");
    clear_screen();
    play();
    write("\n");

}

Sine Wave

#! /usr/bin/env pike

// Sine Wave

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

// This version in Pike:
//  Copyright (c) 2024, Marcos Cruz (programandala.net)
//  SPDX-License-Identifier: Fair
//
// Written on 2024-12-17.
//
// Last modified: 20250313T0101+0100.

void clear_screen() {
    write("\x1B[0;0H\x1B[2J");
}

array(string) word = ({"", ""});

void set_words() {
    clear_screen();
    array(string) order = ({"first", "second"});
    for (int n = 0; n <= 1; n += 1) {
        while (word[n] == "") {
            write("Enter the " + order[n] + " word: ");
            word[n] = Stdio.stdin->gets();
        }
    }
}

void print_credits() {
    clear_screen();
    write("Sine Wave\n\n");
    write("Original version in BASIC:\n");
    write("    Creative Computing (Morristown, New Jersey, USA), ca. 1980.\n\n");
    write("This version in Pike:\n");
    write("    Copyright (c) 2024, Marcos Cruz (programandala.net)\n");
    write("    SPDX-License-Identifier: Fair\n\n");
    write("Press Enter to start the program. ");
    Stdio.stdin->gets();
}

void draw() {
    clear_screen();
    bool even = false;
    for (float angle = 0.0; angle <= 40.0; angle += 0.25) {
        int spaces = (int) (26.0 + floor(25.0 * sin(angle)));
        for (int i = 0; i < spaces; i += 1)
            write(" ");
        write(word[even] + "\n");
        even = !even;
    }
}

void main() {
    print_credits();
    set_words();
    draw();
}

Slots

#!/usr/bin/env pike

// 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 Pike:
//  Copyright (c) 2025, Marcos Cruz (programandala.net)
//  SPDX-License-Identifier: Fair
//
// Written on 2025-03-11.
//
// Last modified: 20250324T2051+0100.

// Terminal {{{1
// =============================================================================

constant BLACK = 0;
constant RED = 1;
constant GREEN = 2;
constant YELLOW = 3;
constant BLUE = 4;
constant MAGENTA = 5;
constant CYAN = 6;
constant WHITE = 7;
constant DEFAULT = 9;

constant STYLE_OFF = 20;
constant FOREGROUND = 30;
constant BACKGROUND = 40;
constant BRIGHT = 60;

constant NORMAL_STYLE = 0;

void move_cursor_home() {
    write("\x1B[H");
}

void hide_cursor() {
    write("\x1B[?25l");
}

void show_cursor() {
    write("\x1B[?25h");
}

void set_style(int style) {
    write("\x1B[%dm", style);
}

void reset_attributes() {
    set_style(NORMAL_STYLE);
}

void erase_screen() {
    write("\x1B[2J");
}

void clear_screen() {
    erase_screen();
    reset_attributes();
    move_cursor_home();
}

// Data {{{1
// =============================================================================

constant REELS = 3;

array(string) image = ({" BAR  ", " BELL ", "ORANGE", "LEMON ", " PLUM ", "CHERRY"});
constant BAR = 0; // position of "BAR" in `image`.
array(int) color = ({
    FOREGROUND + WHITE,
    FOREGROUND + CYAN,
    FOREGROUND + YELLOW,
    FOREGROUND + BRIGHT + YELLOW,
    FOREGROUND + BRIGHT + WHITE,
    FOREGROUND + BRIGHT + RED });
constant MAX_BET = 100;
constant MIN_BET = 1;

// User input {{{1
// =============================================================================

string accept_string(string prompt) {
    write(prompt);
    return Stdio.stdin->gets();
}

int accept_integer(string prompt) {
    // NB The casting accepts any valid integer at the start of the string
    // and ignores the rest;  if no valid integer is found at the start of
    // the string, zero is returned.
    return (int) accept_string(prompt);
}

// Credits and instructions {{{1
// =============================================================================

void print_credits() {
    clear_screen();
    write("Slots\n");
    write("A slot machine simulation.\n\n");
    write("Original version in BASIC:\n");
    write("    Creative computing (Morristown, New Jersey, USA).\n");
    write("    Produced by Fred Mirabelle and Bob Harper on 1973-01-29.\n\n");
    write("This version in Pike:\n");
    write("    Copyright (c) 2025, Marcos Cruz (programandala.net)\n");
    write("    SPDX-License-Identifier: Fair\n\n");
    accept_string("Press Enter for instructions. ");
}

void print_instructions() {
    clear_screen();
    write("You are in the H&M casino, in front of one of our\n");
    write("one-arm bandits. Bet from %d to %d USD (or 0 to quit).\n\n",
        MIN_BET, MAX_BET);
    accept_string("Press Enter to start. ");
}

// Game {{{1
// =============================================================================

int won(int prize, int bet) {
    switch (prize) {
        case 2:
            write("DOUBLE!\n");
            break;
        case 5:
            write("*DOUBLE BAR*\n");
            break;
        case 10:
            write("**TOP DOLLAR**\n");
            break;
        case 100:
            write("***JACKPOT***\n");
    }
    write("You won!\n");
    return (prize + 1) * bet;
}

void show_standings(int usd) {
    write("Your standings are %d USD.\n", usd);
}

void print_reels(array(int) reel) {
    move_cursor_home();
    foreach (reel, int r) {
        set_style(color[r]);
        write("[%s] ", image[r]);
    }
    set_style(NORMAL_STYLE);
    write("\n");
}

void init_reels(array(int) reel) {
    int images = (sizeof(image));
    for (int i = 0; i < sizeof(reel); i += 1) {
        reel[i] = random(images);
    }
}

void spin_reels(array(int) reel) {
    constant DURATION_IN_SECONDS = 2;
    hide_cursor();
    int first_second = time();
    while (time() - first_second < DURATION_IN_SECONDS) {
        init_reels(reel);
        print_reels(reel);
    }
    show_cursor();
}

void play() {

    int standings = 0;
    int bet = 0;
    array(int) reel = allocate(REELS);
    int equals = 0;
    int bars = 0;

    init_reels(reel);

    play_loop: while (true) {

        bet_loop: while (true) {
            clear_screen();
            print_reels(reel);
            bet = accept_integer("Your bet (or 0 to quit): ");
            if (bet > MAX_BET) {
                write("House limits are %d USD.\n", MAX_BET);
                accept_string("Press Enter to try again. ");
            } else if (bet < MIN_BET) {
                string confirmation = accept_string("Type \"q\" to confirm you want to quit. ");
                if (confirmation == "q" || confirmation == "Q") {
                    break play_loop;
                }
            } else {
                break bet_loop;
            } // bet check

        } // bet loop

        clear_screen();
        spin_reels(reel);
        equals = sizeof(reel) - sizeof(Array.uniq(reel));
        equals += (equals > 0);
        bars = Array.count(reel, BAR);

        switch (equals) {
            case 3:
                if (bars == 3) {
                    standings += won(100, bet);
                } else {
                    standings += won(10, bet);
                }
                break;
            case 2:
                if (bars == 2) {
                    standings += won(5, bet);
                } else {
                    standings += won(2, bet);
                }
                break;
            default:
                write("You lost.\n");
                standings -= bet;
        } // prize check

        show_standings(standings);
        accept_string("Press Enter to continue. ");

    } // play loop

    show_standings(standings);

    if (standings < 0) {
        write("Pay up!  Please leave your money on the terminal.\n");
    } else if (standings > 0) {
        write("Collect your winnings from the H&M cashier.\n");
    } else {
        write("Hey, you broke even.\n");
    }

}

// Main {{{1
// =============================================================================

void main() {
    print_credits();
    print_instructions();
    play();
}

Stars

#! /usr/bin/env pike

// Stars

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

// This version in Pike:
//  Copyright (c) 2025, Marcos Cruz (programandala.net)
//  SPDX-License-Identifier: Fair
//
// Written on 2025-03-08.
//
// Last modified: 20250308T1701+0100.

string accept_string(string prompt) {
    write(prompt);
    return Stdio.stdin->gets();
}

int accept_integer(string prompt) {
    // NB The casting accepts any valid integer at the start of the string
    // and ignores the rest;  if no valid integer is found at the start of
    // the string, zero is returned.
    return (int) accept_string(prompt);
}

int accept_valid_integer(string prompt) {
    int n = 0;
    while (n <= 0) {
        n = accept_integer(prompt);
        if (n <= 0) {
            write("Integer greater than zero expected.\n");
        }
    }
    return n;
}

bool is_yes(string s) {
    switch(lower_case(s)) {
        case "ok":
        case "y":
        case "yeah":
        case "yes":
            return true;
        default:
            return false;
    }
}

void main() {
    string name = accept_string("What is your name? ");
    write("Hello, %s.\n", name);
    do {
        int number = accept_valid_integer("How many stars do you want? ");
        write("%s\n", "*" * number);
    } while (is_yes(accept_string("Do you want more stars? ")));
}

Strings

#! /usr/bin/env pike

// Strings

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

// This version in Pike:
//  Copyright (c) 2025, Marcos Cruz (programandala.net)
//  SPDX-License-Identifier: Fair
//
// Written on 2025-03-10, 2025-03-12.
//
// Last modified: 20250312T1809+0100.

string accept_string(string prompt) {
    write(prompt);
    return Stdio.stdin->gets();
}

int accept_integer(string prompt) {
    // NB The casting accepts any valid integer at the start of the string
    // and ignores the rest;  if no valid integer is found at the start of
    // the string, zero is returned.
    return (int) accept_string(prompt);
}

int accept_valid_integer(string prompt) {
    int n = 0;
    while (n <= 0) {
        n = accept_integer(prompt);
        if (n <= 0) {
            write("Integer greater than zero expected.\n");
        }
    }
    return n;
}

void main() {

    string s = accept_string("Enter a string: ");
    int n = accept_valid_integer("Enter an integer: ");

    write("ASC(\"%[0]s\") --> (int) \"%[0]s\"[0] --> %[1]d\n", s, (int) s[0]);
    write("CHR$(%[0]d) --> sprintf(\"%%c\", %[0]d) --> \"%[1]s\"\n", n, sprintf("%c", n));
    write("LEFT$(\"%[0]s\", %[1]d) --> \"%[0]s\"[..%[1]d - 1] --> \"%[2]s\"\n", s, n, s[..n - 1]);
    write("MID$(\"%[0]s\", %[1]d) --> \"%[0]s\"[%[1]d - 1..] --> \"%[2]s\"\n", s, n, s[n - 1..]);
    write("MID$(\"%[0]s\", %[1]d, 3) --> \"%[0]s\"[%[1]d - 1 .. %[1]d - 1 + 3 - 1] --> \"%[2]s\"\n", s, n, s[n - 1 .. n - 1 + 3 - 1]);
    write("RIGHT$(\"%[0]s\", %[1]d) --> \"%[0]s\"[sizeof(%[0]s) - %[1]d..] --> \"%[2]s\"\n", s, n, s[sizeof(s) - n..]);
    write("LEN(\"%[0]s\") --> sizeof(\"%[0]s\") --> %[1]d\n", s, sizeof(s));
    write("VAL(\"%[0]s\") --> (float) \"%[0]s\" --> %[1]f\n", s, (float) s);
    write("STR$(%[0]d) --> (string) %[0]d --> \"%[1]s\"\n", n, (string) n);
    write("SPC(%[0]d) --> \" \" * %[0]d -> \"%[1]s\"\n", n, " " * n);

}

Xchange

#!/usr/bin/env pike

// Xchange

// Original version in BASIC:
//  Written by Thomas C. McIntire, 1979.
//  Published in "The A to Z Book of Computer Games", 1979.
//  https://archive.org/details/The_A_to_Z_Book_of_Computer_Games/page/n269/mode/2up
//  https://github.com/chaosotter/basic-games

// This improved remake in Pike:
//  Copyright (c) 2025, Marcos Cruz (programandala.net)
//  SPDX-License-Identifier: Fair
//
// Written on 2025-03-12.
//
// Last modified: 20250731T1954+0200.

// Terminal {{{1
// =============================================================================

constant BLACK = 0;
constant RED = 1;
constant GREEN = 2;
constant YELLOW = 3;
constant BLUE = 4;
constant MAGENTA = 5;
constant CYAN = 6;
constant WHITE = 7;
constant DEFAULT = 9;

constant STYLE_OFF = 20;
constant FOREGROUND = 30;
constant BACKGROUND = 40;
constant BRIGHT = 60;

constant NORMAL_STYLE = 0;

void move_cursor_home() {
    write("\x1B[H");
}

void set_cursor_position(int line, int column) {
    write("\x1B[%d;%dH", line, column);
}

void set_cursor_coord(array(int) coord) {
    set_cursor_position(coord[0], coord[1]);
}

void hide_cursor() {
    write("\x1B[?25l");
}

void show_cursor() {
    write("\x1B[?25h");
}

void set_style(int style) {
    write("\x1B[%dm", style);
}

void reset_attributes() {
    set_style(NORMAL_STYLE);
}

void erase_line_to_end() {
    write("\x1B[K");
}

void erase_screen_to_end() {
    write("\x1B[J");
}

void erase_screen() {
    write("\x1B[2J");
}

void clear_screen() {
    erase_screen();
    reset_attributes();
    move_cursor_home();
}

// Data {{{1
// =============================================================

constant BOARD_INK = FOREGROUND + BRIGHT + CYAN;
constant DEFAULT_INK = FOREGROUND + WHITE;
constant INPUT_INK = FOREGROUND + BRIGHT + GREEN;
constant INSTRUCTIONS_INK = FOREGROUND + YELLOW;
constant TITLE_INK = FOREGROUND + BRIGHT + RED;

constant BLANK = "*";

constant GRID_HEIGHT = 3; // cell rows
constant GRID_WIDTH = 3; // cell columns

constant CELLS = GRID_WIDTH * GRID_HEIGHT;

array(string) pristine_grid = allocate(CELLS, "");

constant GRIDS_ROW = 3; // screen row where the grids are printed
constant GRIDS_COLUMN = 5; // screen column where the left grid is printed
constant CELLS_GAP = 2; // distance between the grid cells, in screen rows or columns
constant GRIDS_GAP = 16; // screen columns between equivalent cells of the grids

constant FIRST_PLAYER = 0;
constant MAX_PLAYERS = 4;

array(array(string)) grid = allocate(MAX_PLAYERS, allocate(CELLS, ""));

array(bool) is_playing = allocate(MAX_PLAYERS, false);

int players = 0;

constant QUIT_COMMAND = "X";

enum axis { Y, X }; // to use with coord arrays instead of 0 and 1, for clarity

// User input {{{1
// =============================================================

string accept_string(string prompt) {
    write(prompt);
    return Stdio.stdin->gets();
}

int accept_integer_or_0(string prompt) {
    // NB The casting accepts any valid integer at the start of the string
    // and ignores the rest;  if no valid integer is found at the start of
    // the string, zero is returned.
    return (int) accept_string(prompt);
}

int get_integer(string|void prompt) {
    prompt = prompt || "";
    set_style(INPUT_INK);
    int n = accept_integer_or_0(prompt);
    set_style(DEFAULT_INK);
    return n;
}

string get_string(string|void prompt) {
    prompt = prompt || "";
    set_style(INPUT_INK);
    string s = accept_string(prompt);
    set_style(DEFAULT_INK);
    return s;
}

void press_enter(string prompt) {
    accept_string(prompt);
}

bool is_yes(string s) {
    switch(lower_case(s)) {
        case "ok":
        case "y":
        case "yeah":
        case "yes":
            return true;
        default:
            return false;
    }
}

bool is_no(string s) {
    switch(lower_case(s)) {
        case "n":
        case "no":
        case "nope":
            return true;
        default:
            return false;
    }
}

// Print the given prompt, wait until the user enters a valid yes/no string,
// and return `true` for "yes" or `false` for "no".
//
bool yes(string prompt) {
    while (true) {
        string answer = get_string(prompt);
        if (is_yes(answer)) {
            return true;
        }
        if (is_no(answer)) {
            return false;
        }
    }
}

// Title, instructions and credits {{{1
// =============================================================

void print_title() {
    set_style(TITLE_INK);
    write("Xchange\n");
    set_style(DEFAULT_INK);
}

void print_credits() {
    print_title();
    write("\nOriginal version in BASIC:\n");
    write("    Written by Thomas C. McIntire, 1979.\n");
    write("    Published in \"The A to Z Book of Computer Games\", 1979.\n");
    write("    https://archive.org/details/The_A_to_Z_Book_of_Computer_Games/page/n269/mode/2up\n");
    write("    https://github.com/chaosotter/basic-games\n");
    write("This improved remake in Pike:\n");
    write("    Copyright (c) 2025, Marcos Cruz (programandala.net)\n");
    write("    SPDX-License-Identifier: Fair\n");
}

void print_instructions() {
    print_title();
    set_style(INSTRUCTIONS_INK);
    write("\nOne or two may play.  If two, you take turns.  A grid looks like this:\n\n");
    set_style(BOARD_INK);
    write("    F G D\n");
    write("    A H %s\n", BLANK);
    write("    E B C\n\n");
    set_style(INSTRUCTIONS_INK);
    write("But it should look like this:\n\n");
    set_style(BOARD_INK);
    write("    A B C\n");
    write("    D E F\n");
    write("    G H %s\n\n", BLANK);
    set_style(INSTRUCTIONS_INK);
    write("You may exchange any one letter with the '%s', but only one that's adjacent:\n", BLANK);
    write("above, below, left, or right.  Not all puzzles are possible, and you may enter\n");
    write("'%s' to give up.\n\n", QUIT_COMMAND);
    write("Here we go...\n");
    set_style(DEFAULT_INK);
}

// Grids {{{1
// =============================================================

// Print the given player's grid title.
//
void print_grid_title(int player) {
    set_cursor_position(GRIDS_ROW, GRIDS_COLUMN + (player * GRIDS_GAP));
    write("Player %d", player + 1);
}

// Return the cursor position of the given player's grid cell.
//
array(int) cell_position(int player, int cell) {
    int grid_row = cell / GRID_HEIGHT;
    int grid_column = cell % GRID_WIDTH;
    int title_margin = players > 1 ? 2 : 0;
    int row = GRIDS_ROW + title_margin + grid_row;
    int column = GRIDS_COLUMN +
        (grid_column * CELLS_GAP) +
        (player * GRIDS_GAP);
    return ({ row, column });
}

// Return the cursor position of the given player's grid prompt.
//
array(int) grid_prompt_position_of(int player) {
    array(int) coord = cell_position(player, CELLS);
    int row = coord[0];
    int column = coord[1];
    return ({ row + 1, column });
}

// Print the given player's grid, in the given or default color.
//
void print_grid(int player, int|void color) {
    color = color || BOARD_INK;
    if (players > 1) {
        print_grid_title(player);
    }
    set_style(color);
    for (int cell = 0; cell < CELLS; cell += 1) {
        set_cursor_coord(cell_position(player, cell));
        write(grid[player][cell]);
    }
    set_style(DEFAULT_INK);
}

// Print the current players' grids.
//
void print_grids() {
    for (int player = 0; player < players; player += 1) {
        if (is_playing[player]) {
            print_grid(player);
        }
    }
    write("\n");
    erase_screen_to_end();
}

// Scramble the grid of the given player.
//
void scramble_grid(int player) {
    for (int cell = 0; cell < CELLS; cell += 1) {
        int random_cell = random(CELLS);
        // Exchange the contents of the current cell with that of the random one.
        string  tmp = grid[player][cell];
        grid[player][cell] = grid[player][random_cell];
        grid[player][random_cell] = tmp;
    }
}

// Init the grids.
//
void init_grids() {
    grid[0] = copy_value(pristine_grid);
    scramble_grid(0);
    for (int player = 1; player < players; player += 1) {
        grid[player] = copy_value(grid[0]);
    }
}

// Messages {{{1
// =============================================================

// Return a message prefix for the given player.
//
string player_prefix(int player) {
    return players > 1 ? sprintf("Player %d: ", player + 1) : "";
}

// Return the cursor position of the given player's messages, adding the given
// row increment, which defaults to zero.
//
array(int) message_position(int player, int|void row_inc) {
    row_inc = row_inc || 0;
    array(int) prompt_coord = grid_prompt_position_of(player);
    return ({ prompt_coord[Y] + 2 + row_inc, 1 });
}

// Print the given message about the given player, adding the given row
// increment, which defaults to zero, to the default cursor coordinates.
//
void print_message(string message, int player, int|void row_inc) {
    row_inc = row_inc || 0;
    set_cursor_coord(message_position(player, row_inc));
    write("%s%s", player_prefix(player), message);
    erase_line_to_end();
    write("\n");
}

// Erase the last message about the given player.
//
void erase_message(int player) {
    set_cursor_coord(message_position(player));
    erase_line_to_end();
}

// Game loop {{{1
// =============================================================

// Return a message with the players range.
//
string players_range_message() {
    if (MAX_PLAYERS == 2) {
        return "1 or 2";
    } else {
        return sprintf("from 1 to %d", MAX_PLAYERS);
    }
}

// Return the number of players, asking the user if needed.
//
int number_of_players() {
    int players = 0;
    print_title();
    write("\n");
    if (MAX_PLAYERS == 1) {
        players = 1;
    } else {
        while (players < 1 || players > MAX_PLAYERS) {
            string prompt = sprintf("Number of players (%s): ", players_range_message());
            players = get_integer(prompt);
        }
    }
    return players;
}

// Is the given cell the first one on a grid row?
//
bool is_first_cell_of_a_grid_row(int cell) {
    return cell % GRID_WIDTH == 0;
}

// Is the given cell the last one on a grid row?
//
bool is_last_cell_of_a_grid_row(int cell) {
    return (cell + 1) % GRID_WIDTH == 0;
}

// Are the given cells adjacent?
//
bool are_cells_adjacent(int cell_1, int cell_2) {
    return (cell_2 == cell_1 + 1 && !is_first_cell_of_a_grid_row(cell_2)) ||
        (cell_2 == cell_1 + GRID_WIDTH) ||
        (cell_2 == cell_1 - 1 && !is_last_cell_of_a_grid_row(cell_2)) ||
        (cell_2 == cell_1 - GRID_WIDTH);
}

// If the given player's character cell is a valid move, i.e. it is adjacent to
// the blank cell, return the blank cell; otherwise return an empty string.
//
int|string position_to_cell(int player, int char_cell) {
    for (int cell = 0; cell < CELLS; cell += 1) {
        if (grid[player][cell] == BLANK) {
            if (are_cells_adjacent(char_cell, cell)) {
                return cell;
            } else {
                break;
            }
        }
    }
    print_message(sprintf("Illegal move \"%s\".", grid[player][char_cell]), player);
    return "";
}

// If the given player's command is valid, i.e. a grid character, return its
// position; otherwise return an empty string.
//
int|string command_to_position(int player, string command) {
    if (command != BLANK) {
        for (int position = 0; position < CELLS; position += 1) {
            if (command == grid[player][position]) {
                return position;
            }
        }
    }
    print_message(sprintf("Invalid character \"%s\".", command), player);
    return "";
}

// Forget the given player, who quitted.
//
void forget_player(int player) {
    is_playing[player] = false;
    print_grid(player, DEFAULT_INK);
}

// Play the turn of the given player.
//
void play_turn(int player) {
    int blank_position = 0;
    int character_position = 0;

    if (is_playing[player]) {
        while (true) {
            while (true) {
                array(int) coord = grid_prompt_position_of(player);
                set_cursor_coord(coord);
                erase_line_to_end();
                set_cursor_coord(coord);
                string command = upper_case(String.trim(get_string("Move: ")));
                if (command == QUIT_COMMAND) {
                    forget_player(player);
                    return;
                }
                int|string position = command_to_position(player, command);
                if (intp(position)) {
                    character_position = position;
                    break;
                }
            }
            int|string position = position_to_cell(player, character_position);
            if (intp(position)) {
                blank_position = position;
                break;
            }
        }
        erase_message(player);
        grid[player][blank_position] = grid[player][character_position];
        grid[player][character_position] = BLANK;
    }
}

// Play the turns of all players.
//
void play_turns() {
    for (int player = 0; player < players; player += 1) {
        play_turn(player);
    }
}

// Is someone playing?
//
bool is_someone_playing() {
    for (int player = 0; player < players; player += 1) {
        if (is_playing[player]) {
            return true;
        }
    }
    return false;
}

bool has_an_empty_grid(int player) {
    for (int i = 0; i < CELLS; i += 1) {
        if (grid[player][i] != "") {
            return false;
        }
    }
    return true;
}

// Has someone won? If so, print a message for every winner and return `true`
// otherwise just return `false`.
//
bool has_someone_won() {
    int winners = 0;
    for (int player = 0; player < players; player += 1) {
        if (is_playing[player]) {
            if (has_an_empty_grid(player)) {
                winners += 1;
                if (winners > 0) {
                    print_message(
                        sprintf("You're the winner%s!", (winners > 1) ? ", too" : ""),
                        player,
                        winners - 1);
                }
            }
        }
    }
    return winners > 0;
}

// Init the game.
//
void init_game() {
    clear_screen();
    players = number_of_players();
    for (int player = 0; player < players; player += 1) {
        is_playing[player] = true;
    }
    clear_screen();
    print_title();
    init_grids();
    print_grids();
}

// Play the game.
//
void play() {
    init_game();
    while (is_someone_playing()) {
        play_turns();
        print_grids();
        if (has_someone_won()) {
            break;
        }
    }
}

// Main {{{1
// =============================================================

void init_once() {

    // Init the pristine grid.
    constant FIRST_CHAR_CODE = 'A';
    for (int cell = 0; cell < CELLS - 1; cell += 1) {
        pristine_grid[cell] = sprintf("%c", FIRST_CHAR_CODE + cell);
    }
    pristine_grid[CELLS - 1] = BLANK;
}

// Return `true` if the player does not want to play another game; otherwise
// return `false`.
//
bool enough() {
    set_cursor_coord(grid_prompt_position_of(FIRST_PLAYER));
    return !yes("Another game? ");
}

void main() {
    init_once();

    clear_screen();
    print_credits();
    press_enter("\nPress the Enter key to read the instructions. ");

    clear_screen();
    print_instructions();
    press_enter("\nPress the Enter key to start. ");

    while (true) {
        play();
        if (enough()) {
            break;
        }
    }
    write("So long…\n");
}

Rilataj paĝoj

Basics off
Metaprojekto pri la projektoj «Basics of…».
Basics of 8th
Konverto de malnovaj BASIC-programoj al 8th por lerni la fundamentojn de ĉi-tiu lingvo.
Basics of Ada
Konverto de malnovaj BASIC-programoj al Ada por lerni la fundamentojn de ĉi-tiu lingvo.
Basics of Arturo
Konverto de malnovaj BASIC-programoj al Arturo por lerni la fundamentojn de ĉi-tiu lingvo.
Basics of C#
Konverto de malnovaj BASIC-programoj al C# por lerni la fundamentojn de ĉi-tiu lingvo.
Basics of C3
Konverto de malnovaj BASIC-programoj al C3 por lerni la fundamentojn de ĉi-tiu lingvo.
Basics of Chapel
Konverto de malnovaj BASIC-programoj al Chapel por lerni la fundamentojn de ĉi-tiu lingvo.
Basics of Clojure
Konverto de malnovaj BASIC-programoj al Clojure por lerni la fundamentojn de ĉi-tiu lingvo.
Basics of Crystal
Konverto de malnovaj BASIC-programoj al Crystal por lerni la fundamentojn de ĉi-tiu lingvo.
Basics of D
Konverto de malnovaj BASIC-programoj al D por lerni la fundamentojn de ĉi-tiu lingvo.
Basics of Elixir
Konverto de malnovaj BASIC-programoj al Elixir por lerni la fundamentojn de ĉi-tiu lingvo.
Basics of F#
Konverto de malnovaj BASIC-programoj al F# por lerni la fundamentojn de ĉi-tiu lingvo.
Basics of Factor
Konverto de malnovaj BASIC-programoj al Factor por lerni la fundamentojn de ĉi-tiu lingvo.
Basics of FreeBASIC
Konverto de malnovaj BASIC-programoj al FreeBASIC por lerni la fundamentojn de ĉi-tiu lingvo.
Basics of Gleam
Konverto de malnovaj BASIC-programoj al Gleam por lerni la fundamentojn de ĉi-tiu lingvo.
Basics of Go
Konverto de malnovaj BASIC-programoj al Go por lerni la fundamentojn de ĉi-tiu lingvo.
Basics of Hare
Konverto de malnovaj BASIC-programoj al Hare por lerni la fundamentojn de ĉi-tiu lingvo.
Basics of Haxe
Konverto de malnovaj BASIC-programoj al Haxe por lerni la fundamentojn de ĉi-tiu lingvo.
Basics of Icon
Konverto de malnovaj BASIC-programoj al Icon por lerni la fundamentojn de ĉi-tiu lingvo.
Basics of Io
Konverto de malnovaj BASIC-programoj al Io por lerni la fundamentojn de ĉi-tiu lingvo.
Basics of Janet
Konverto de malnovaj BASIC-programoj al Janet por lerni la fundamentojn de ĉi-tiu lingvo.
Basics of Julia
Konverto de malnovaj BASIC-programoj al Julia por lerni la fundamentojn de ĉi-tiu lingvo.
Basics of Kotlin
Konverto de malnovaj BASIC-programoj al Kotlin por lerni la fundamentojn de ĉi-tiu lingvo.
Basics of Lobster
Konverto de malnovaj BASIC-programoj al Lobster por lerni la fundamentojn de ĉi-tiu lingvo.
Basics of Lua
Konverto de malnovaj BASIC-programoj al Lua por lerni la fundamentojn de ĉi-tiu lingvo.
Basics of Nature
Konverto de malnovaj BASIC-programoj al Nature por lerni la fundamentojn de ĉi-tiu lingvo.
Basics of Neat
Konverto de malnovaj BASIC-programoj al Neat por lerni la fundamentojn de ĉi-tiu lingvo.
Basics of Neko
Konverto de malnovaj BASIC-programoj al Neko por lerni la fundamentojn de ĉi-tiu lingvo.
Basics of Nelua
Konverto de malnovaj BASIC-programoj al Nelua por lerni la fundamentojn de ĉi-tiu lingvo.
Basics of Nim
Konverto de malnovaj BASIC-programoj al Nim por lerni la fundamentojn de ĉi-tiu lingvo.
Basics of Nit
Konverto de malnovaj BASIC-programoj al Nit por lerni la fundamentojn de ĉi-tiu lingvo.
Basics of Oberon-07
Konverto de malnovaj BASIC-programoj al Oberon-07 por lerni la fundamentojn de ĉi-tiu lingvo.
Basics of OCaml
Konverto de malnovaj BASIC-programoj al OCaml por lerni la fundamentojn de ĉi-tiu lingvo.
Basics of Odin
Konverto de malnovaj BASIC-programoj al Odin por lerni la fundamentojn de ĉi-tiu lingvo.
Basics of Pony
Konverto de malnovaj BASIC-programoj al Pony por lerni la fundamentojn de ĉi-tiu lingvo.
Basics of Python
Konverto de malnovaj BASIC-programoj al Python por lerni la fundamentojn de ĉi-tiu lingvo.
Basics of Racket
Konverto de malnovaj BASIC-programoj al Racket por lerni la fundamentojn de ĉi-tiu lingvo.
Basics of Raku
Konverto de malnovaj BASIC-programoj al Raku por lerni la fundamentojn de ĉi-tiu lingvo.
Basics of Retro
Konverto de malnovaj BASIC-programoj al Retro por lerni la fundamentojn de ĉi-tiu lingvo.
Basics of Rexx
Konverto de malnovaj BASIC-programoj al Rexx por lerni la fundamentojn de ĉi-tiu lingvo.
Basics of Ring
Konverto de malnovaj BASIC-programoj al Ring por lerni la fundamentojn de ĉi-tiu lingvo.
Basics of Rust
Konverto de malnovaj BASIC-programoj al Rust por lerni la fundamentojn de ĉi-tiu lingvo.
Basics of Scala
Konverto de malnovaj BASIC-programoj al Scala por lerni la fundamentojn de ĉi-tiu lingvo.
Basics of Scheme
Konverto de malnovaj BASIC-programoj al Scheme por lerni la fundamentojn de ĉi-tiu lingvo.
Basics of Styx
Konverto de malnovaj BASIC-programoj al Styx por lerni la fundamentojn de ĉi-tiu lingvo.
Basics of Swift
Konverto de malnovaj BASIC-programoj al Swift por lerni la fundamentojn de ĉi-tiu lingvo.
Basics of V
Konverto de malnovaj BASIC-programoj al V por lerni la fundamentojn de ĉi-tiu lingvo.
Basics of Vala
Konverto de malnovaj BASIC-programoj al Vala por lerni la fundamentojn de ĉi-tiu lingvo.
Basics of Zig
Konverto de malnovaj BASIC-programoj al Zig por lerni la fundamentojn de ĉi-tiu lingvo.

Eksteraj rilataj ligiloj