Basics of C#

Descrition del contenete del págine

Conversion de old BASIC-programas a C# por aprender lu elementari de ti-ci lingue.

Etiquettes:

3D Plot

// 3D Plot

// Original version in BASIC, "3D Plot":
//  3-D Plot (by Mark Bramhall), 1978.
//  Creative Computing's BASIC Games.
//  - http://vintage-basic.net/games.html
//  - http://vintage-basic.net/bcg/3dplot.bas
//  - https://www.atariarchives.org/basicgames/showpage.php?page=167

// This version in C#:
//  Copyright (c) 2024, Marcos Cruz (programandala.net)
//  SPDX-License-Identifier: Fair
//
// Written on 2024-12-20.
//
// Last modified: 20251205T1528+0100.

using System;

class D3Plot
{
    static void PrintCredits()
    {
        Console.WriteLine("3D Plot\n");
        Console.WriteLine("Original version in BASIC:");
        Console.WriteLine("    Creative computing (Morristown, New Jersey, USA), ca. 1980.\n");
        Console.WriteLine("This version in C#:");
        Console.WriteLine("    Copyright (c) 2024, Marcos Cruz (programandala.net)");
        Console.WriteLine("    SPDX-License-Identifier: Fair\n");
        Console.Write("Press any key to start. ");
        Console.ReadKey();
    }

    static double A(double z)
    {
        return 30 * Math.Exp(-z * z / 100);
    }

    static void Draw()
    {
        const int WIDTH = 56;
        const char SPACE = ' ';
        const char DOT = '*';

        int l = 0;
        int z = 0;
        int y = 0;
        int y1 = 0;
        char[] line = new char[WIDTH];

        double x = -30.0;
        while (x <= 30.0)
        {
            for (int i = 0; i < WIDTH; i++)
            {
                line[i] = SPACE;
            }

            l = 0;
            y1 = 5 * (int)(Math.Sqrt(900 - x * x) / 5);

            y = y1;
            while (y >= -y1)
            {
                z = (int)(25 + A(Math.Sqrt(x * x + (double)(y * y))) - 0.7 * y);
                if (z > l)
                {
                    l = z;
                    line[z] = DOT;
                };
                y += -5;
            } // y loop

            foreach (char c in line)
            {
                Console.Write(c);
            }
            Console.WriteLine();

            x += 1.5;
        } // x loop
    }

    static void Main()
    {
        Console.Clear();
        PrintCredits();
        Console.Clear();
        Draw();
    }
}

Bagels

// Bagels

// Original version in BASIC:
//  By D. Resek, P. Rowe, 1978.
//  Creative Computing's BASIC Games.
//  - http://vintage-basic.net/games.html
//  - http://vintage-basic.net/bcg/bagels.bas
//  - http://www.atariarchives.org/basicgames/showpage.php?page=9

// This version in C#:
//  Copyright (c) 2024, Marcos Cruz (programandala.net)
//  SPDX-License-Identifier: Fair
//
// Written on 2024-12-25.
//
// Last modified: 20251205T1530+0100.

using System;
using System.Linq;

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

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

    const int DIGITS = 3;

    static int[] randomDigit = new int[DIGITS];

    // Return three random digits.
    //
    static int[] RandomDigits()
    {
        Random rand = new Random();

        for (int i = 0; i < DIGITS; i++)
        {
            while (true)
            {
                digitLoop:
                randomDigit[i] = rand.Next(10);
                for (int j = 0; j < i; j++)
                {
                    if (i != j && randomDigit[i] == randomDigit[j])
                    {
                        goto digitLoop;
                    }
                }
                break;
            }
        }
        return randomDigit;
    }

    // Return `true` if any of the elements of the given array, which contains
    // only numbers in inclusive range 0..9, is repeated; otherwise return
    // `false`.
    //
    static bool IsAnyRepeated(int[] num)
    {
        bool[] present = new bool[10];
        foreach (int n in num)
        {
            if (present[n])
                return true;
            else
                present[n] = true;
        }
        return false;
    }

    // Print the given prompt and update the array whose address is given with a
    // three-digit number from the user.
    //
    static void GetInput(string prompt, ref int[] userDigit)
    {
        // XXX TODO Create a local array, appending every digit after checking
        // the contents, making `IsAnyRepeated` unnecessary.

        while (true)
        {
            getLoop:
            Console.Write(prompt);
            string input = Console.ReadLine();
            if (input.Length != DIGITS)
            {
                Console.WriteLine($"Remember it's a {DIGITS}-digit number.");
                continue;
            }
            char digit;
            for (int i = 0; i < input.Length; i++)
            {
                digit = input[i];
                if (Char.IsDigit(digit))
                {
                    userDigit[i] = ((int) digit) - ((int) '0');
                }
                else
                {
                    Console.WriteLine("What?");
                    goto getLoop;
                }
            }
            if (IsAnyRepeated(userDigit))
            {
                Console.WriteLine("Remember my number has no two digits the same.");
                continue;
            }
            break;
        }
    }

    // Return `true` if the given string is "yes" or a synonym.
    //
    static bool IsYes(string s)
    {
        string[] validOptions = {"ok", "y", "yeah", "yes"};
        return validOptions.Contains(s.ToLower());
    }

    // Return `true` if the given string is "no" or a synonym.
    //
    static bool IsNo(string s)
    {
        string[] validOptions = {"n", "no", "nope"};
        return validOptions.Contains(s.ToLower());
    }

    // Print the given prompt, wait until the user enters a valid yes/no string,
    // and return `true` for "yes" or `false` for "no".
    //
    static bool Yes(string prompt)
    {
        while (true)
        {
            Console.Write(prompt);
            string answer = Console.ReadLine();
            if (IsYes(answer))
            {
                return true;
            }
            if (IsNo(answer))
            {
                return false;
            }
        }
    }

    static void Play()
    {
        const int TRIES = 20;
        int score = 0;
        int fermi = 0; // counter
        int pico = 0; // counter
        int[] userNumber = new int[DIGITS];
        while (true)
        {
            Console.Clear();
            int[] computerNumber = RandomDigits();
            Console.WriteLine("O.K.  I have a number in mind.");
            for (int guess = 1; guess <= TRIES; guess++)
            {
                GetInput($"Guess #{guess}: ", ref userNumber);
                fermi = 0;
                pico = 0;
                for (int i = 0; i < DIGITS; i++)
                {
                    for (int j = 0; j < DIGITS; j++)
                    {
                        if (userNumber[i] == computerNumber[j])
                        {
                            if (i == j)
                            {
                                fermi += 1;
                            }
                            else
                            {
                                pico += 1;
                            }
                        }
                    }
                }
                for (int i = 0; i < pico; i++)
                    Console.Write("PICO ");
                for (int i = 0; i < fermi; i++)
                    Console.Write("FERMI ");
                if (pico + fermi == 0)
                    Console.Write("BAGELS");
                Console.WriteLine();
                if (fermi == DIGITS)
                {
                    break;
                }
            }
            if (fermi == DIGITS)
            {
                Console.WriteLine("You got it!!!");
                score += 1;
            }
            else
            {
                Console.WriteLine("Oh well.");
                Console.Write($"That's {TRIES} guesses.  My number was ");
                for (int i = 0; i < DIGITS; i++)
                {
                    Console.Write(computerNumber[i]);
                }
                Console.WriteLine(".");
            }
            if (!Yes("Play again? "))
            {
                break;
            }
        }
        if (score != 0)
        {
            Console.WriteLine($"A {score}-point bagels, buff!!");
        }
        Console.WriteLine("Hope you had fun.  Bye.");
    }

    static void Main()
    {
        PrintCredits();
        PrintInstructions();
        Play();
    }
}

Bug

// Bug

// Original version in BASIC:
//  Brian Leibowitz, 1978.
//  Creative Computing's BASIC Games.
//  - http://vintage-basic.net/games.html
//  - http://vintage-basic.net/bcg/bug.bas
//  - https://www.atariarchives.org/basicgames/showpage.php?page=30
//  - http://www.retroarchive.org/cpm/games/ccgames.zip

// This version in C#:
//  Copyright (c) 2024, Marcos Cruz (programandala.net)
//  SPDX-License-Identifier: Fair
//
// Written in 2024-12-20/21.
//
// Last modified: 20251205T1532+0100.

using System;

class BugGame
{
    class ABug
    {
        internal bool body = false;
        internal bool neck = false;
        internal bool head = false;
        internal int feelers = 0;
        internal char feelerType = ' ';
        internal bool tail = false;
        internal int legs = 0;
    }

    class Player
    {
        internal string pronoun = "";
        internal string possessive = "";
        internal ABug bug = new ABug();
    }

    static Player computer = new Player();
    static Player human = new Player();

    enum Part {body = 1, neck, head, feeler, tail, leg};
    static int parts = Enum.GetNames(typeof(Part)).Length;

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

    static void PrintCredits()
    {
        Console.Clear();
        Console.WriteLine("Bug\n");
        Console.WriteLine("Original version in BASIC:");
        Console.WriteLine("    Brian Leibowitz, 1978.");
        Console.WriteLine("    Creative computing (Morristown, New Jersey, USA), 1978.\n");
        Console.WriteLine("This version in C#:");
        Console.WriteLine("    Copyright (c) 2024, Marcos Cruz (programandala.net)");
        Console.WriteLine("    SPDX-License-Identifier: Fair\n");
        Console.Write("Press Enter to read the instructions. ");
        Console.ReadKey();
    }

    // Return the given string with its first character in uppercase and the
    // rest in lowercase.
    //
    static string Capitalized(string str)
    {
        if (string.IsNullOrEmpty(str))
        {
            return string.Empty;
        }
        else
        {
            return char.ToUpper(str[0]) + str.Substring(1).ToLower();
        }
    }

    // Write the given string the given number of times.
    //
    static void WriteTimes(string s, int n)
    {
        for (int t = 0; t < n; t++)
        {
            Console.Write(s);
        }
    }

    // Print a table with the description of the bug parts.
    //
    static void PrintPartsTable()
    {
        const int COLUMNS = 3;
        const int COLUMN_WIDTH = 8;
        const int COLUMN_SEPARATION = 2;

        // Headers

        string[] header = {"Number", "Part", "Quantity"};
        for (int i = 0; i < COLUMNS; i++)
        {
            Console.Write(header[i].PadRight(COLUMN_WIDTH + COLUMN_SEPARATION));
        }
        Console.WriteLine();

        // Rulers

        for (int i = 0; i < COLUMNS; i++)
        {
            WriteTimes("-", COLUMN_WIDTH);
            if (i != COLUMNS - 1)
            {
                WriteTimes(" ", COLUMN_SEPARATION);
            }
        }
        Console.WriteLine();

        // Data

        int[] partQuantity = new int[parts + 1];

        partQuantity[(int) Part.body] = 1;
        partQuantity[(int) Part.neck] = 1;
        partQuantity[(int) Part.head] = 1;
        partQuantity[(int) Part.feeler] = 2;
        partQuantity[(int) Part.tail] = 1;
        partQuantity[(int) Part.leg] = 6;

        for (Part p = Part.body; (int) p < parts; p++)
        {
            Console.Write($"{(int) p}".PadRight(COLUMN_WIDTH + COLUMN_SEPARATION));
            Console.Write(Capitalized(Enum.GetName(typeof(Part), p).PadRight(COLUMN_WIDTH + COLUMN_SEPARATION)));
            Console.WriteLine(partQuantity[(int) p]);
        }
    }

    static void PrintInstructions()
    {
        Console.Clear();
        Console.WriteLine("Bug\n");
        Console.WriteLine("The object is to finish your bug before I finish mine. Each number");
        Console.WriteLine("stands for a part of the bug body.\n");
        Console.WriteLine("I will roll the die for you, tell you what I rolled for you, what the");
        Console.WriteLine("number stands for, and if you can get the part. If you can get the");
        Console.WriteLine("part I will give it to you. The same will happen on my turn.\n");
        Console.WriteLine("If there is a change in either bug I will give you the option of");
        Console.WriteLine("seeing the pictures of the bugs. The numbers stand for parts as");
        Console.WriteLine("follows:\n");
        PrintPartsTable();
        Console.Write("\nPress Enter to start. ");
        Console.ReadKey();
    }

    // Print the given bug.
    //
    static void PrintBug(ABug bug)
    {
        if (bug.feelers > 0)
        {
            for (int i = 0; i < FEELER_LENGTH; i++)
            {
                Console.Write("        ");
                for (int j = 0; j < bug.feelers; j++)
                {
                    Console.Write($" {bug.feelerType}");
                }
                Console.WriteLine();
            }
        }
        if (bug.head)
        {
            Console.WriteLine("        HHHHHHH");
            Console.WriteLine("        H     H");
            Console.WriteLine("        H O O H");
            Console.WriteLine("        H     H");
            Console.WriteLine("        H  V  H");
            Console.WriteLine("        HHHHHHH");
        }
        if (bug.neck)
        {
            for (int i = 0; i < NECK_LENGTH; i++)
            {
                Console.WriteLine("          N N");
            }
        }
        if (bug.body)
        {
            Console.WriteLine("     BBBBBBBBBBBB");
            for (int i = 0; i < BODY_HEIGHT; i++)
            {
                Console.WriteLine("     B          B");
            }
            if (bug.tail)
            {
                Console.WriteLine("TTTTTB          B");
            }
            Console.WriteLine("     BBBBBBBBBBBB");
        }
        if (bug.legs > 0)
        {
            for (int i = 0; i < LEG_LENGTH; i++)
            {
                Console.Write("    ");
                for (int j = 0; j < bug.legs; j++)
                {
                    Console.Write(" L");
                }
                Console.WriteLine();
            }
        }
    }

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

    // Return a random number from 1 to 6 (inclusive).
    //
    static int Dice()
    {
        Random rand = new Random();
        return rand.Next(6) + 1;
    }

    // Array to convert a number to its equilavent text.
    //
    static string[] asText =
    {
        "no",
        "a",
        "two",
        "three",
        "four",
        "five",
        "six" }; // MAX_LEGS

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

    // Add the given part to the given player's bug.
    //
    static bool AddPart(Part part, Player player)
    {
        bool changed = false;
        switch (part)
        {
        case Part.body:
            if (player.bug.body)
            {
                Console.WriteLine($", but {player.pronoun} already have a body.");
            }
            else
            {
                Console.WriteLine($"; {player.pronoun} now have a body:");
                player.bug.body = true;
                changed = true;
            }
            break;
        case Part.neck:
            if (player.bug.neck)
            {
                Console.WriteLine($", but {player.pronoun} already have a neck.");
            }
            else if (!player.bug.body)
            {
                Console.WriteLine($", but {player.pronoun} need a body first.");
            }
            else
            {
                Console.WriteLine($"; {player.pronoun} now have a neck:");
                player.bug.neck = true;
                changed = true;
            }
            break;
        case Part.head:
            if (player.bug.head)
            {
                Console.WriteLine($", but {player.pronoun} already have a head.");
            }
            else if (!player.bug.neck)
            {
                Console.WriteLine($", but {player.pronoun} need a a neck first.");
            }
            else
            {
                Console.WriteLine($"; {player.pronoun} now have a head:");
                player.bug.head = true;
                changed = true;
            }
            break;
        case Part.feeler:
            if (player.bug.feelers == MAX_FEELERS)
            {
                Console.WriteLine($", but {player.pronoun} have two feelers already.");
            }
            else if (!player.bug.head)
            {
                Console.WriteLine($", but {player.pronoun} need a head first.");
            }
            else
            {
                player.bug.feelers += 1;
                Console.Write($"; {player.pronoun} now have",
                    Plural(player.bug.feelers, "feeler"));
                Console.WriteLine(":");
                changed = true;
            }
            break;
        case Part.tail:
            if (player.bug.tail)
            {
                Console.WriteLine($", but {player.pronoun} already have a tail.");
            }
            else if (!player.bug.body)
            {
                Console.WriteLine($", but {player.pronoun} need a body first.");
            }
            else
            {
                Console.WriteLine($"; {player.pronoun} now have a tail:");
                player.bug.tail = true;
                changed = true;
            }
            break;
        case Part.leg:
            if (player.bug.legs == MAX_LEGS)
            {
                Console.WriteLine($", but {player.pronoun} have {asText[MAX_LEGS]} feet already.");
            }
            else if (!player.bug.body)
            {
                Console.WriteLine($", but {player.pronoun} need a body first.");
            }
            else
            {
                player.bug.legs += 1;
                Console.Write($"; {player.pronoun} now have {Plural(player.bug.legs, "leg")}");
                Console.WriteLine(":");
                changed = true;
            }
            break;
        }
        return changed;
    }

    // Ask the user to press the Enter key, wait for the input, then erase the;
    // prompt text.
    //
    static void Prompt()
    {
        Console.Write("Press Enter to roll the dice. ");
        Console.ReadKey();
    }

    // Play one turn for the given player, rolling the dice and updating his bug.
    //
    static void Turn(Player player)
    {
        Prompt();
        int number = Dice();
        Part part = (Part) number;
        Console.Write($"{Capitalized(player.pronoun)} rolled a {number} ({part})");
        if (AddPart(part, player))
        {
            Console.WriteLine();
            PrintBug(player.bug);
        }
        Console.WriteLine();
    }

    // Print a message about the winner.
    //
    static void PrintWinner()
    {
        if (Finished(human.bug) && Finished(computer.bug))
        {
            Console.WriteLine("Both of our bugs are finished in the same number of turns!");
        }
        else if (Finished(human.bug))
        {
            Console.WriteLine($"{human.possessive} bug is finished.");
        }
        else if (Finished(computer.bug))
        {
            Console.WriteLine($"{computer.possessive} bug is finished.");
        }
    }

    static bool GameOver()
    {
        return Finished(human.bug) || Finished(computer.bug);
    }

    // Execute the game loop.
    //
    static void Play()
    {
        Console.Clear();
        while (!GameOver())
        {
            Turn(human);
            Turn(computer);
        }
        PrintWinner();
    }

    // Init the players' data before a new game.
    //
    static void Init()
    {
        human.pronoun = "you";
        human.possessive = "Your";
        human.bug.feelerType = 'A';
        computer.pronoun = "I";
        computer.possessive = "My";
        computer.bug.feelerType = 'F';
    }

    static void Main()
    {
        Init();
        PrintCredits();
        PrintInstructions();
        Play();
        Console.WriteLine("I hope you enjoyed the game, play it again soon!!");
    }
}

Bunny

// Bunny

// Original version in BASIC:
//  Anonymous, 1978.
//  Creative Computing's BASIC Games.
//  - http://vintage-basic.net/games.html
//  - http://vintage-basic.net/bcg/bunny.bas
//  - http://www.retroarchive.org/cpm/games/ccgames.zip

// This version in C#:
//  Copyright (c) 2024, Marcos Cruz (programandala.net)
//  SPDX-License-Identifier: Fair
//
// Written on 2024-12-20.
//
// Last modified: 20251205T1532+0100.

using System;

class Bunny
{
    static void PrintCredits()
    {
        Console.WriteLine("Bunny\n");
        Console.WriteLine("Original version in BASIC:");
        Console.WriteLine("    Creative Computing (Morristown, New Jersey, USA), 1978.\n");
        Console.WriteLine("This version in C#:");
        Console.WriteLine("    Copyright (c) 2024, Marcos Cruz (programandala.net)");
        Console.WriteLine("    SPDX-License-Identifier: Fair\n");
        Console.Write("Press Enter to start. ");
        Console.ReadKey();
    }

    const int WIDTH = 53;
    static char[] line = new char[WIDTH]; // buffer

    static void clearLine()
    {
        for (int c = 0; c < WIDTH; c++)
        {
            line[c] = ' ';
        }
    }

    static char[] letter = {'B', 'U', 'N', 'N', 'Y'};

    const int EOL = -1; // end of line identifier

    static 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 };

    static int dataIndex = 0;

    static int datum()
    {
        dataIndex += 1;
        return data[dataIndex - 1];
    }

    static void Draw()
    {
        clearLine();
        while (dataIndex < data.Length)
        {
            int firstColumn = datum();
            if (firstColumn == EOL)
            {
                Console.WriteLine(line);
                clearLine();
            }
            else
            {
                int lastColumn = datum();
                for (int c = firstColumn; c <= lastColumn; c++)
                {
                    line[c] = letter[c % letter.Length];
                }
            }
        }
    }

    static void Main()
    {
        Console.Clear();
        PrintCredits();
        Console.Clear();
        Draw();
    }
}

Chase

// 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 C#:
//  Copyright (c) 2024, Marcos Cruz (programandala.net)
//  SPDX-License-Identifier: Fair
//
// Written on 2025-01-01.
//
// Last modified 20251205T1534+0100.

using System;
using System.Linq;

class Chase
{
    // Globals {{{1
    // =============================================================

    // Colors

    const ConsoleColor DEFAULT_INK = ConsoleColor.White;
    const ConsoleColor INPUT_INK = ConsoleColor.Green;
    const ConsoleColor INSTRUCTIONS_INK = ConsoleColor.DarkYellow;
    const ConsoleColor TITLE_INK = ConsoleColor.Red;

    // Arena

    const int ARENA_WIDTH = 20;
    const int ARENA_HEIGHT = 10;
    const int ARENA_LAST_X = ARENA_WIDTH - 1;
    const int ARENA_LAST_Y = ARENA_HEIGHT - 1;
    const int ARENA_ROW = 2;

    static string[,] arena = new string[ARENA_HEIGHT, ARENA_WIDTH];

    const string EMPTY = " ";
    const string FENCE = "X";
    const string MACHINE = "m";
    const string HUMAN = "@";

    const int FENCES = 15; // inner obstacles, not the border

    // The end

    enum End
    {
        NotYet,
        Quit,
        Electrified,
        Killed,
        Victory,
    }

    static End theEnd;

    // Machines

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

    static int[] machineX = new int[MACHINES];
    static int[] machineY = new int[MACHINES];
    static bool[] operative = new bool[MACHINES];
    static int destroyedMachines; // counter

    // Human

    static int humanX;
    static int humanY;

    // Random numbers generator

    static Random rand = new Random();

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

    // Print the given prompt and wait until the user enters a string.
    //
    static string InputString(string prompt = "")
    {
        Console.ForegroundColor = INPUT_INK;
        Console.Write(prompt);
        string result = Console.ReadLine();
        Console.ForegroundColor = DEFAULT_INK;
        return result;
    }

    // Print the given prompt and wait until the user presses Enter.
    //
    static void PressEnter(string prompt)
    {
        InputString(prompt);
    }

    // Return `true` if the given string is "yes" or a synonym.
    //
    static bool IsYes(string s)
    {
        string[] validOptions = {"ok", "y", "yeah", "yes"};
        return validOptions.Contains(s.ToLower());
    }

    // Return `true` if the given string is "no" or a synonym.
    //
    static bool IsNo(string s)
    {
        string[] validOptions = {"n", "no", "nope"};
        return validOptions.Contains(s);
    }

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

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

    const string TITLE = "Chase";

    // Print the title at the current cursor position.
    //
    static void PrintTitle()
    {
        Console.ForegroundColor = TITLE_INK;
        Console.WriteLine(TITLE);
        Console.ForegroundColor = DEFAULT_INK;
    }

    static void PrintCredits()
    {
        PrintTitle();
        Console.WriteLine("\nOriginal version in BASIC:");
        Console.WriteLine("    Anonymous.");
        Console.WriteLine("    Published in \"The Best of Creative Computing\", Volume 2, 1977.");
        Console.WriteLine("    https://www.atariarchives.org/bcc2/showpage.php?page=253");
        Console.WriteLine("\nThis version in C#:");
        Console.WriteLine("    Copyright (c) 2024, Marcos Cruz (programandala.net)");
        Console.WriteLine("    SPDX-License-Identifier: Fair");
    }

    // Print the game instructions and wait for a key.
    //
    static void PrintInstructions()
    {
        PrintTitle();
        Console.ForegroundColor = INSTRUCTIONS_INK;
        Console.WriteLine($"\nYou ({HUMAN}) are in a high voltage maze with {MACHINES}");
        Console.WriteLine($"security machines ({MACHINE}) trying to kill you.");
        Console.WriteLine($"You must maneuver them into the maze ({FENCE}) to survive.\n");
        Console.WriteLine("Good luck!\n");
        Console.WriteLine("The movement commands are the following:\n");
        Console.WriteLine("    ↖  ↑  ↗");
        Console.WriteLine("    NW N NE");
        Console.WriteLine("  ←  W   E  →");
        Console.WriteLine("    SW S SE");
        Console.WriteLine("    ↙  ↓  ↘");
        Console.WriteLine("\nPlus 'Q' to end the game.");
        Console.ForegroundColor = DEFAULT_INK;
    }

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

    // Display the arena at the top left corner of the screen.
    //
    static void PrintArena()
    {
        Console.SetCursorPosition(0, ARENA_ROW);
        for (int y = 0; y <= ARENA_LAST_Y; y++)
        {
            for (int x = 0; x <= ARENA_LAST_X; x++)
            {
                Console.Write(arena[y, x]);
            }
            Console.WriteLine();
        }
    }

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

    // Return a random integer in the given inclusive range.
    //
    static int RandomIntInInclusiveRange(int min, int max)
    {
        return rand.Next(max - min + 1) + min;
    }

    // Place the given string at a random empty position of the arena and return
    // the coordinates.
    //
    static (int y, int x) Place(string s)
    {
        int y;
        int x;

        while (true)
        {
            y = RandomIntInInclusiveRange(1, ARENA_LAST_Y - 1);
            x = RandomIntInInclusiveRange(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.
    //
    static void InhabitArena()
    {
        for (int m = 0; m < MACHINES; m++)
        {
            (machineY[m], machineX[m]) = Place(MACHINE);
            operative[m] = true;
        }
        for (int _ = 0; _ < FENCES; _++) Place(FENCE);
        (humanY, humanX) = Place(HUMAN);
    }

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

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

    // Init the game.
    //
    static void InitGame()
    {
        CleanArena();
        InhabitArena();
        destroyedMachines = 0;
        theEnd = End.NotYet;
    }

    // Move the given machine.
    //
    static void MoveMachine(int m)
    {
        int maybe;
        arena[machineY[m], machineX[m]] = EMPTY;

        maybe = rand.Next(2);
        if (machineY[m] > humanY)
        {
            machineY[m] -= maybe;
        }
        else if (machineY[m] < humanY)
        {
            machineY[m] += maybe;
        }

        maybe = rand.Next(2);
        if ((machineX[m] > humanX))
        {
            machineX[m] -= maybe;
        }
        else if ((machineX[m] < humanX))
        {
            machineX[m] += maybe;
        }

        if (arena[machineY[m], machineX[m]] == EMPTY)
        {
            arena[machineY[m], machineX[m]] = MACHINE;
        }
        else if (arena[machineY[m], machineX[m]] == FENCE)
        {
            operative[m] = false;
            destroyedMachines += 1;
            if (destroyedMachines == MACHINES)
            {
                theEnd = End.Victory;
            }
        }
        else if (arena[machineY[m], machineX[m]] == HUMAN)
        {
            theEnd = End.Killed;
        }
    }

    // Maybe move the given operative machine.
    //
    static void MaybeMoveMachine(int m)
    {
        if (rand.Next(MACHINES_DRAG) == 0)
        {
            MoveMachine(m);
        }
    }

    // Move the operative machines.
    //
    static void MoveMachines()
    {
        for (int m = 0; m < MACHINES; m++)
        {
            if (operative[m])
            {
                MaybeMoveMachine(m);
            }
        }
    }

    // Erase the current line to the right from the position of the cursor.
    //
    static void EraseLineRight()
    {
        int y = Console.CursorTop;
        int x = Console.CursorLeft;
        string blank = new String(' ', Console.WindowWidth - x - 1);

        Console.Write(blank);
        Console.SetCursorPosition(x, y);
    }

    // Read a user command; update `theEnd` accordingly and return the direction
    // increments.
    //
    static (int yInc, int xInc) GetMove()
    {
        int yInc = 0;
        int xInc = 0;

        Console.WriteLine();
        EraseLineRight();
        string command = InputString("Command: ").ToLower();

        switch (command)
        {
            case "q"  : theEnd = End.Quit; break;
            case "sw" : yInc = +1; xInc = -1; break;
            case "s"  : yInc = +1; break;
            case "se" : yInc = +1; xInc = +1; break;
            case "w"  :             xInc = -1; break;
            case "e"  :             xInc = +1; break;
            case "nw" : yInc = -1; xInc = -1; break;
            case "n"  : yInc = -1; break;
            case "ne" : yInc = -1; xInc = +1; break;
        }
        return (yInc, xInc);
    }

    static void Play()
    {
        int yInc;
        int xInc;

        while (true) { // game loop

            Console.Clear();
            PrintTitle();
            InitGame();

            while (true) { // action loop
                PrintArena();
                (yInc, xInc) = GetMove();
                if (theEnd == End.NotYet)
                {
                    if (yInc != 0 || xInc != 0)
                    {
                        arena[humanY, humanX] = EMPTY;
                        if (arena[humanY + yInc, humanX + xInc] == FENCE)
                        {
                            theEnd = End.Electrified;
                        }
                        else if (arena[humanY + yInc, humanX + xInc] == MACHINE)
                        {
                            theEnd = End.Killed;
                        }
                        else
                        {
                            arena[humanY, humanX] = EMPTY;
                            humanY = humanY + yInc;
                            humanX = humanX + xInc;
                            arena[humanY, humanX] = HUMAN;
                            PrintArena();
                            MoveMachines();
                        }
                    }
                }
                if (theEnd != End.NotYet)
                {
                    break;
                }
            }// action loop;

            switch (theEnd)
            {
                case End.Quit :
                    Console.WriteLine("\nSorry to see you quit.");
                    break;
                case End.Electrified :
                    Console.WriteLine("\nZap! You touched the fence!");
                    break;
                case End.Killed :
                    Console.WriteLine("\nYou have been killed by a lucky machine.");
                    break;
                case End.Victory :
                    Console.WriteLine("\nYou are lucky, you destroyed all machines.");
                    break;
            }

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

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

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

    static void Main()
    {
        Console.ForegroundColor = DEFAULT_INK;

        Console.Clear();
        PrintCredits();

        PressEnter("\nPress the Enter key to read the instructions. ");
        Console.Clear();
        PrintInstructions();

        PressEnter("\nPress the Enter key to start. ");
        Play();
    }
}

Diamond

// Diamond

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

// This version in C#:
//  Copyright (c) 2024, Marcos Cruz (programandala.net)
//  SPDX-License-Identifier: Fair
//
// Written on 2024-12-20.
//
// Last modified 20251205T1534+0100.

using System;

class Diamond
{
    static void Main()
    {
        const int LINES = 17;
        int i = 1;
        int j = 0;

        i = 1;
        while (i <= LINES / 2 + 1)
        {
            j = 1;
            while (j <= (LINES + 1) / 2 - i + 1)
            {
                Console.Write(" ");
                j += 1;
            }
            j = 1;
            while (j <= i * 2 - 1)
            {
                Console.Write("*");
                j += 1;
            }
            Console.WriteLine();
            i += 1;
        }
        i = 1;
        while (i <= LINES / 2)
        {
            j = 1;
            while (j <= i + 1)
            {
                Console.Write(" ");
                j += 1;
            }
            j = 1;
            while (j <= ((LINES + 1) / 2 - i) * 2 - 1)
            {
                Console.Write("*");
                j += 1;
            }
            Console.WriteLine();
            i += 1;
        }
    }
}

Hammurabi

// 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.
//  - http://web.archive.org/web/20150215091831/http://www.dunnington.u-net.com/public/basicgames/
//  - http://web.archive.org/web/20150120012304/http://www.dunnington.u-net.com/public/basicgames/HMRABI
//
// Modernized versions:
//  - https://archive.org/details/hamurabi.qb64
//
// More details:
//  - https://en.wikipedia.org/wiki/Hamurabi_(video_game)
//  - https://www.mobygames.com/game/22232/hamurabi/

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

using System;

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

    const ConsoleColor DEFAULT_INK = ConsoleColor.White;
    const ConsoleColor INPUT_INK = ConsoleColor.Green;
    const ConsoleColor INSTRUCTIONS_INK = ConsoleColor.DarkYellow;
    const ConsoleColor RESULT_INK = ConsoleColor.Cyan;
    const ConsoleColor SPEECH_INK = ConsoleColor.Magenta;
    const ConsoleColor TITLE_INK = ConsoleColor.White;
    const ConsoleColor WARNING_INK = ConsoleColor.Red;

    enum Result
    {
        VeryGood,
        NotTooBad,
        Bad,
        VeryBad,
    }

    static int acres;
    static int bushelsEatenByRats;
    static int bushelsHarvested;
    static int bushelsHarvestedPerAcre;
    static int bushelsInStore;
    static int bushelsToFeedWith;
    static int dead;
    static int infants;
    static int irritation; // counter from 0 to 99 (inclusive)
    static int population;
    static int starvedPeoplePercentage;
    static int totalDead;

    static Random rand = new Random();

    // Return a random number from 1 to 5 (inclusive).
    //
    static int Random1To5()
    {
        return rand.Next(5) + 1;
    }

    // Return the proper wording for `n` persons, using the given or default words
    // for singular and plural forms.
    //
    static string persons
    (
        int n,
        string singular = "person",
        string plural = "people"
    )
    {
        switch (n)
        {
            case 0:
                return "nobody";
            case 1:
                return $"one {singular}";
            default:
                return $"{n} {plural}";
        }
    }

    static void PrintInstructions()
    {
        Console.ForegroundColor = INSTRUCTIONS_INK;

        Console.WriteLine("Hammurabi is a simulation game in which you, as the ruler of the ancient");
        Console.WriteLine("kingdom of Sumeria, Hammurabi, manage the resources.");

        Console.WriteLine("\nYou may buy and sell land with your neighboring city-states for bushels of");
        Console.WriteLine($"grain ― the price will vary between {MIN_HARVESTED_BUSHELS_PER_ACRE} and {MAX_HARVESTED_BUSHELS_PER_ACRE} bushels per acre.  You also must");
        Console.WriteLine("use grain to feed your people and as seed to plant the next year's crop");

        Console.WriteLine("\nYou will quickly find that a certain number of people can only tend a certain");
        Console.WriteLine("amount of land and that people starve if they are not fed enough.  You also");
        Console.WriteLine("have the unexpected to contend with such as a plague, rats destroying stored");
        Console.WriteLine("grain, and variable harvests.");

        Console.WriteLine("\nYou will also find that managing just the few resources in this game is not a");
        Console.WriteLine("trivial job.  The crisis of population density rears its head very rapidly.");

        Console.WriteLine($"\nTry your hand at governing ancient Sumeria for a {YEARS}-year term of office.");

        Console.ForegroundColor = DEFAULT_INK;
    }

    static void PressEnter(string prompt = "> ")
    {
        InputString(prompt);
    }

    // Print the given prompt in the correspondent color, wait until the user
    // enters a string and return.
    //
    static string InputString(string prompt = "")
    {
        Console.ForegroundColor = INPUT_INK;
        Console.Write(prompt);
        string result = Console.ReadLine();
        Console.ForegroundColor = DEFAULT_INK;
        return result;
    }

    // Print the given prompt in the correspondent color, wait until the user
    // enters a valid integer and return.
    //
    static int InputInt(string prompt = "")
    {
        Console.ForegroundColor = INPUT_INK;

        int number;

        while (true)
        {
            Console.Write(prompt);
            try
            {
                number = (int) Int64.Parse(Console.ReadLine());
                break;
            }
            catch
            {
                Console.WriteLine("Integer expected.");
            }
        }
        Console.ForegroundColor = DEFAULT_INK;
        return number;
    }

    static void PrintCredits()
    {
        Console.ForegroundColor = TITLE_INK;
        Console.WriteLine("Hammurabi");
        Console.WriteLine("\nOriginal program:");
        Console.WriteLine("  Written in FOCAL on a DEP PDP-8 by Rick Merrill, 1969.");
        Console.WriteLine("\nBASIC port:");
        Console.WriteLine("  Ported from FOCAL and modified for Edusystem 70 by David Ahl, c. 1973.");
        Console.WriteLine("  Modified for 8K Microsoft BASIC by Peter Turnbull, c. 1978.");
        Console.WriteLine("\nThis improved remake in C#:");
        Console.WriteLine("  Copyright (c) 2024, Marcos Cruz (programandala.net)");
        Console.WriteLine("  SPDX-License-Identifier: Fair");
        Console.ForegroundColor = DEFAULT_INK;
    }

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

    // Return the description of the given year as the previous one.
    //
    static string Previous(int year)
    {
        if (year == 0)
        {
            return "the previous year";
        }
        else
        {
            return $"your {year}{OrdinalSuffix(year)} year";
        }
    }

    static void PrintAnnualReport(int year)
    {
        Console.Clear();
        Console.ForegroundColor = SPEECH_INK;
        Console.WriteLine("Hammurabi, I beg to report to you.");
        Console.ForegroundColor = DEFAULT_INK;

        Console.WriteLine
        (
            "\nIn {0}, {1} starved and {2} {3} born.",
            Previous(year),
            persons(dead),
            persons(infants, "infant", "infants"),
            infants > 1 ? "were" : "was"
        );

        population += infants;

        double plagueChance = rand.NextDouble();
        if (year > 0 ? plagueChance <= PLAGUE_CHANCE : false)
        {
            population = (int) population / 2;
            Console.ForegroundColor = WARNING_INK;
            Console.WriteLine("A horrible plague struck!  Half the people died.");
            Console.ForegroundColor = DEFAULT_INK;
        }

        Console.WriteLine($"The population is {population}.");
        Console.WriteLine($"The city owns {acres} acres.");
        Console.WriteLine
        (
            "You harvested {0} bushels ({1} per acre).",
            bushelsHarvested,
            bushelsHarvestedPerAcre
        );
        if (bushelsEatenByRats > 0)
        {
            Console.WriteLine($"The rats ate {bushelsEatenByRats} bushels.");
        }
        Console.WriteLine($"You have {bushelsInStore} bushels in store.");
        bushelsHarvestedPerAcre =
            (int) (RANGE_OF_HARVESTED_BUSHELS_PER_ACRE * rand.NextDouble()) +
            MIN_HARVESTED_BUSHELS_PER_ACRE;
        Console.WriteLine($"Land is trading at {bushelsHarvestedPerAcre} bushels per acre.\n");
    }

    static void SayBye()
    {
        Console.ForegroundColor = DEFAULT_INK;
        Console.WriteLine("\nSo long for now.\n");
    }

    static void QuitGame()
    {
        SayBye();
        Environment.Exit(0);
    }

    static void Relinquish()
    {
        Console.ForegroundColor = SPEECH_INK;
        Console.WriteLine("\nHammurabi, I am deeply irritated and cannot serve you anymore.");
        Console.WriteLine("Please, get yourself another steward!");
        Console.ForegroundColor = DEFAULT_INK;
        QuitGame();
    }

    static void IncreaseIrritation()
    {
        irritation += 1 + rand.Next(IRRITATION_STEP);
        if (irritation >= MAX_IRRITATION)
        {
            Relinquish();
        } // this never returns
    }

    static void PrintIrritated(string adverb)
    {
        Console.WriteLine($"The steward seems {adverb} irritated.");
    }

    static void ShowIrritation()
    {
        if (irritation < IRRITATION_STEP || irritation < IRRITATION_STEP * 2)
        {
            PrintIrritated("slightly");
        }
        else if (irritation < IRRITATION_STEP * 3)
        {
            PrintIrritated("quite");
        }
        else if (irritation < IRRITATION_STEP * 4)
        {
            PrintIrritated("very");
        }
        else
        {
            PrintIrritated("profoundly");
        }
    }

    // Print a message begging to repeat an ununderstandable input.
    //
    static void BegRepeat()
    {
        IncreaseIrritation(); // this may never return
        Console.ForegroundColor = SPEECH_INK;
        Console.WriteLine("I beg your pardon?  I did not understand your order.");
        Console.ForegroundColor = DEFAULT_INK;
        ShowIrritation();
    }

    // Print a message begging to repeat a wrong input, because there's only `n`
    // items of `name`.
    //
    static void BegThinkAgain(int n, string name)
    {
        IncreaseIrritation(); // this may never return
        Console.ForegroundColor = SPEECH_INK;
        Console.WriteLine($"I beg your pardon?  You have only {n} {name}.  Now then…");
        Console.ForegroundColor = DEFAULT_INK;
        ShowIrritation();
    }

    // Buy or sell land.
    //
    static void Trade()
    {
        int acresToBuy;
        int acresToSell;

        while (true)
        {
            acresToBuy = InputInt("How many acres do you wish to buy? (0 to sell): ");
            if (acresToBuy < 0)
            {
                BegRepeat(); // this may never return
                continue;
            }
            if (bushelsHarvestedPerAcre * acresToBuy <= bushelsInStore)
            {
                break;
            }
            BegThinkAgain(bushelsInStore, "bushels of grain");
        }

        if (acresToBuy != 0)
        {
            Console.WriteLine($"You buy {acresToBuy} acres.");
            acres += acresToBuy;
            bushelsInStore -= bushelsHarvestedPerAcre * acresToBuy;
            Console.WriteLine($"You now have {acres} acres and {bushelsInStore} bushels.");
        }
        else
        {
            while (true)
            {
                acresToSell = InputInt("How many acres do you wish to sell?: ");
                if (acresToSell < 0)
                {
                    BegRepeat(); // this may never return
                    continue;
                }
                if (acresToSell < acres)
                {
                    break;
                }
                BegThinkAgain(acres, "acres");
            }

            if (acresToSell > 0)
            {
                Console.WriteLine($"You sell {acresToSell} acres.");
                acres -= acresToSell;
                bushelsInStore += bushelsHarvestedPerAcre * acresToSell;
                Console.WriteLine($"You now have {acres} acres and {bushelsInStore} bushels.");
            }
        }
    }

    // Feed the people.
    //
    static void Feed()
    {
        while (true)
        {
            bushelsToFeedWith = InputInt("How many bushels do you wish to feed your people with?: ");
            if (bushelsToFeedWith < 0)
            {
                BegRepeat(); // this may never return
                continue;
            }
            // Trying to use more grain than is in silos?
            if (bushelsToFeedWith <= bushelsInStore)
            {
                break;
            }
            BegThinkAgain(bushelsInStore, "bushels of grain");
        }

        Console.WriteLine($"You feed your people with {bushelsToFeedWith} bushels.");
        bushelsInStore -= bushelsToFeedWith;
        Console.WriteLine($"You now have {bushelsInStore} bushels");
    }

    // Seed the land.
    //
    static void Seed()
    {
        int acresToSeed;

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

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

            // Enough grain for seed?
            if ((int) acresToSeed / ACRES_A_BUSHEL_CAN_SEED > bushelsInStore)
            {
                BegThinkAgain
                (
                    bushelsInStore,
                    $"bushels of grain,\nand one bushel can seed {ACRES_A_BUSHEL_CAN_SEED} acres"
                );
                continue;
            }

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

            BegThinkAgain
            (
                population,
                $"people to tend the fields,\nand one person can seed {ACRES_A_PERSON_CAN_SEED} acres"
            );
        }

        int bushelsUsedForSeeding = (int) acresToSeed / ACRES_A_BUSHEL_CAN_SEED;
        Console.WriteLine($"You seed {acresToSeed} acres using {bushelsUsedForSeeding} bushels.");
        bushelsInStore -= bushelsUsedForSeeding;
        Console.WriteLine($"You now have {bushelsInStore} bushels.");

        // A bountiful harvest!
        bushelsHarvestedPerAcre = Random1To5();
        bushelsHarvested = acresToSeed * bushelsHarvestedPerAcre;
        bushelsInStore += bushelsHarvested;
    }

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

    static void CheckRats()
    {
        int ratChance = Random1To5();
        bushelsEatenByRats = IsEven(ratChance) ? (int) bushelsInStore / ratChance : 0;
        bushelsInStore -= bushelsEatenByRats;
    }

    // Set the variables to their values in the first year.
    //
    static void Init()
    {
        dead = 0;
        totalDead = 0;
        starvedPeoplePercentage = 0;
        population = 95;
        infants = 5;
        acres = ACRES_PER_PERSON * (population + infants);
        bushelsHarvestedPerAcre = 3;
        bushelsHarvested = acres * bushelsHarvestedPerAcre;
        bushelsEatenByRats = 200;
        bushelsInStore = bushelsHarvested - bushelsEatenByRats;
        irritation = 0;
    }

    static void PrintResult(Result result)
    {
        Console.ForegroundColor = RESULT_INK;

        switch (result)
        {
            case Result.VeryGood :
                Console.WriteLine("A fantastic performance!  Charlemagne, Disraeli and Jefferson combined could");
                Console.WriteLine("not have done better!");
                break;
            case Result.NotTooBad :
                Console.WriteLine("Your performance could have been somewat better, but really wasn't too bad at");
                Console.WriteLine
                (
                    "all. {0} people would dearly like to see you assassinated, but we all have our",
                    (int) ((double) population * .8 * rand.NextDouble())
                );
                Console.WriteLine("trivial problems.");
                break;
            case Result.Bad :
                Console.WriteLine("Your heavy-handed performance smacks of Nero and Ivan IV.  The people");
                Console.WriteLine("(remaining) find you an unpleasant ruler and, frankly, hate your guts!");
                break;
            case Result.VeryBad :
                Console.WriteLine("Due to this extreme mismanagement you have not only been impeached and thrown");
                Console.WriteLine("out of office but you have also been declared national fink!!!");
                break;
        }

        Console.ForegroundColor = DEFAULT_INK;
    }

    static void PrintFinalReport()
    {
        Console.Clear();

        if (starvedPeoplePercentage > 0)
        {
            Console.WriteLine
            (
                "In your {0}-year term of office, {1} percent of the",
                YEARS,
                starvedPeoplePercentage
            );
            Console.WriteLine
            (
                "population starved per year on the average, i.e., a total of {0} people died!\n",
                totalDead
            );
        }

        int acresPerPerson = acres / population;
        Console.WriteLine
        (
            "You started with {0} acres per person and ended with {1}.\n",
            ACRES_PER_PERSON,
            acresPerPerson
        );

        if (starvedPeoplePercentage > 33 || acresPerPerson < 07)
        {
            PrintResult(Result.VeryBad);
        }
        else if (starvedPeoplePercentage > 10 || acresPerPerson < 09)
        {
            PrintResult(Result.Bad);
        }
        else if (starvedPeoplePercentage > 03 || acresPerPerson < 10)
        {
            PrintResult(Result.NotTooBad);
        }
        else
        {
            PrintResult(Result.VeryGood);
        }
    }

    static void CheckStarvation(int year)
    {
            // How many people has been fed?
            int fedPeople = (int) bushelsToFeedWith / BUSHELS_TO_FEED_A_PERSON;

            if (population > fedPeople)
            {
                dead = population - fedPeople;
                starvedPeoplePercentage = ((year - 1) * starvedPeoplePercentage + dead * 100 / population) / year;
                population -= dead;
                totalDead += dead;

                // Starve enough for impeachment?
                if (dead > (int) (.45 * (double) population))
                {
                    Console.ForegroundColor = WARNING_INK;
                    Console.WriteLine($"\nYou starved {dead} people in one year!!!\n");
                    Console.ForegroundColor = DEFAULT_INK;
                    PrintResult(Result.VeryBad);
                    QuitGame();
                }
            }
    }

    static void Govern()
    {
        Init();

        PrintAnnualReport(0);

        for (int year = 1; year <= YEARS; year++)
        {
            Trade();
            Feed();
            Seed();
            CheckRats();

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

            CheckStarvation(year);

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

    static void Main()
    {
        Console.Clear();
        PrintCredits();

        PressEnter("\nPress the Enter key to read the instructions. ");
        Console.Clear();
        PrintInstructions();

        PressEnter("\nPress the Enter key to start. ");
        Govern();

        PressEnter("Press the Enter key to read the final report. ");
        PrintFinalReport();
        SayBye();
    }
}

High Noon

// 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 C#:
//  Copyright (c) 2024, Marcos Cruz (programandala.net)
//  SPDX-License-Identifier: Fair
//
// Written in 2024-12-25/26.
//
// Last modified: 20251205T1540+0100.

using System;
using System.Linq;

class HighNoon
{
    static Random rand = new Random();

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

    const ConsoleColor DEFAULT_COLOR = ConsoleColor.White;
    const ConsoleColor INPUT_COLOR = ConsoleColor.Green;
    const ConsoleColor INSTRUCTIONS_COLOR = ConsoleColor.DarkYellow;
    const ConsoleColor TITLE_COLOR = ConsoleColor.Red;

    const int INITIAL_DISTANCE = 100;
    const int INITIAL_BULLETS = 4;
    const int MAX_WATERING_TROUGHS = 3;

    static int distance; // distance between both gunners, in paces
    static string strategy; // player's strategy

    static int playerBullets;
    static int opponentBullets;

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

    // Print the given prompt and wait until the user enters a string.
    //
    static string GetString(string prompt = "")
    {
        Console.ForegroundColor = INPUT_COLOR;
        Console.Write(prompt);
        string input = Console.ReadLine();
        Console.ForegroundColor = DEFAULT_COLOR;
        return input;
    }

    // Print the given prompt and wait until the user enters an integer.
    //
    static int GetInteger(string prompt = "")
    {
        int n = 0;

        Console.ForegroundColor = INPUT_COLOR;

        while (true)
        {
            try
            {
                n = Int32.Parse(GetString(prompt));
                break;
            }
            catch
            {
            }
        }

        Console.ForegroundColor = DEFAULT_COLOR;
        return n;
    }

    // Return `true` if the given string is "yes" or a synonym.
    //
    static bool IsYes(string s)
    {
        string[] validOptions = {"ok", "y", "yeah", "yes"};
        return validOptions.Contains(s.ToLower());
    }

    // Return `true` if the given string is "no" or a synonym.
    //
    static bool IsNo(string s)
    {
        string[] validOptions = {"n", "no", "nope"};
        return validOptions.Contains(s.ToLower());
    }

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

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

    // Print the title at the current cursor position.
    //
    static void PrintTitle()
    {
        Console.ForegroundColor = TITLE_COLOR;
        Console.WriteLine("High Noon");
        Console.ForegroundColor = DEFAULT_COLOR;
    }

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

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

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

    static string PluralSuffix(int n)
    {
        return n == 1 ? "" : "s";
    }

    static void PrintShellsLeft()
    {
        if (playerBullets == opponentBullets)
        {
            Console.WriteLine($"Both of you have {playerBullets} bullets.");
        }
        else
        {
            Console.WriteLine
            (
                "You now have {0} bullet{1} to Black Bart's {2} bullet{3}.",
                playerBullets,
                PluralSuffix(playerBullets),
                opponentBullets,
                PluralSuffix(opponentBullets)
            );
        }
    }

    static void PrintCheck()
    {
        Console.WriteLine("******************************************************");
        Console.WriteLine("*                                                    *");
        Console.WriteLine("*                 BANK OF DODGE CITY                 *");
        Console.WriteLine("*                  CASHIER'S RECEIT                  *");
        Console.WriteLine("*                                                    *");
        Console.WriteLine("* CHECK NO. {0:0000}                   AUGUST {1}TH, 1889 *",
            rand.Next(1000),
            10 + rand.Next(10));
        Console.WriteLine("*                                                    *");
        Console.WriteLine("*                                                    *");
        Console.WriteLine("*       PAY TO THE BEARER ON DEMAND THE SUM OF       *");
        Console.WriteLine("*                                                    *");
        Console.WriteLine("* TWENTY THOUSAND DOLLARS-------------------$20,000  *");
        Console.WriteLine("*                                                    *");
        Console.WriteLine("******************************************************");
    }

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

    static void MoveTheOpponent()
    {
        int paces = 2 + rand.Next(8);
        Console.WriteLine($"Black Bart moves {paces} 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.
    //
    static bool MaybeMoveTheOpponent(bool silent = false)
    {
        if (rand.Next(2) == 0) { // 50% chances
            MoveTheOpponent();
            return true;
        }
        else
        {
            if (! silent)
            {
                Console.WriteLine("Black Bart stands still.");
            }
            return false;
        }
    }

    static bool MissedShot()
    {
        return rand.NextDouble() * 10 <= (double) 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`.
    //
    static bool TheOpponentFiresAndKills()
    {
        Console.WriteLine("Black Bart fires…");
        opponentBullets -= 1;
        if (MissedShot())
        {
            Console.WriteLine("A miss…");
            switch (opponentBullets)
            {
                case 3:
                    Console.WriteLine("Whew, were you lucky. That bullet just missed your head.");
                    break;
                case 2:
                    Console.WriteLine("But Black Bart got you in the right shin.");
                    break;
                case 1:
                    Console.WriteLine("Though Black Bart got you on the left side of your jaw.");
                    break;
                case 0:
                    Console.WriteLine("Black Bart must have jerked the trigger.");
                    break;
            }
        }
        else
        {
            if (strategy == "j")
            {
                Console.WriteLine("That trick just saved yout life. Black Bart's bullet");
                Console.WriteLine("was stopped by the wood sides of the trough.");
            }
            else
            {
                Console.WriteLine("Black Bart shot you right through the heart that time.");
                Console.WriteLine("You went kickin' with your boots on.");
                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`.
    //
    static bool TheOpponentKillsOrRuns()
    {
        if (distance >= 10 || playerBullets == 0)
        {
            if (MaybeMoveTheOpponent(silent: true))
            {
                return false;
            }
        }
        if (opponentBullets > 0)
        {
            return TheOpponentFiresAndKills();
        }
        else
        {
            if (playerBullets > 0)
            {
                if (rand.Next(2) == 0)
                {
                    {;
                } // 50% chances
                    Console.WriteLine("Now is your chance, Black Bart is out of bullets.");
                }
                else
                {
                    Console.WriteLine("Black Bart just hi-tailed it out of town rather than face you");
                    Console.WriteLine("without a loaded gun. You can rest assured that Black Bart");
                    Console.WriteLine("won't ever show his face around this town again.");
                    return true;
                }
            }
        }
        return false;
    }

    static void Play()
    {
        distance = INITIAL_DISTANCE;
        int wateringTroughs = 0;
        playerBullets = INITIAL_BULLETS;
        opponentBullets = INITIAL_BULLETS;

        while (true)
        {
            Console.WriteLine($"You are now {distance} paces apart from Black Bart.");
            PrintShellsLeft();
            Console.ForegroundColor = INSTRUCTIONS_COLOR;
            Console.WriteLine("\nStrategies:");
            Console.WriteLine("  [A]dvance");
            Console.WriteLine("  [S]tand still");
            Console.WriteLine("  [F]ire");
            Console.WriteLine("  [J]ump behind the watering trough");
            Console.WriteLine("  [G]ive up");
            Console.WriteLine("  [T]urn tail and run");
            Console.ForegroundColor = DEFAULT_COLOR;

            strategy = (GetString("What is your strategy? ")).ToLower();

            switch (strategy)
            {
                case "a": // advance

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

                case "s": // stand still

                    Console.WriteLine("That move made you a perfect stationary target.");
                    break;

                case "f": // fire

                    if (playerBullets == 0)
                    {
                        Console.WriteLine("You don't have any bullets left.");
                    }
                    else
                    {
                        playerBullets -= 1;
                        if (MissedShot())
                        {
                            switch (playerBullets)
                            {
                                case 2:
                                    Console.WriteLine("Grazed Black Bart in the right arm.");
                                    break;
                                case 1:
                                    Console.WriteLine("He's hit in the left shoulder, forcing him to use his right");
                                    Console.WriteLine("hand to shoot with.");
                                    break;
                            }
                            Console.WriteLine("What a lousy shot.");
                            if (playerBullets == 0)
                            {
                                Console.WriteLine("Nice going, ace, you've run out of bullets.");
                                if (opponentBullets != 0)
                                {
                                    Console.WriteLine("Now Black Bart won't shoot until you touch noses.");
                                    Console.WriteLine("You better think of something fast (like run).");
                                }
                            }
                        }
                        else
                        {
                            Console.WriteLine("What a shot, you got Black Bart right between the eyes.");
                            GetString("\nPress the Enter key to get your reward. ");
                            Console.Clear();
                            GetReward();
                            return;
                        }
                    }
                    break;

                case "j": // jump

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

                case "g": // give up

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

                case "t": // turn tail and run

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

                default:

                    Console.WriteLine("You sure aren't going to live very long if you can't even follow directions.");
                    break;
            }; // strategy switch

            if (TheOpponentKillsOrRuns())
            {
                break;
            }

            if (playerBullets + opponentBullets == 0)
            {
                Console.WriteLine("The showdown must end, because nobody has bullets left.");
                break;
            }

            Console.WriteLine();
        }; // showdown loop
    }

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

    static void Main()
    {
        Console.Clear();
        PrintCredits();

        GetString("\nPress the Enter key to read the instructions. ");
        Console.Clear();
        PrintInstructions();

        GetString("\nPress the Enter key to start. ");
        Console.Clear();
        Play();
    }
}

Math

// Math

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

// This version in C#:
//  Copyright (c) 2024, Marcos Cruz (programandala.net)
//  SPDX-License-Identifier: Fair
//
// Written on 2024-12-21.
//
// Last modified: 20251205T1540+0100.

using System;

class vintageBasicMath
{
    static void Main()
    {
        double n;

        while (true)
        {
            Console.Write("Enter a number: ");
            try
            {
                // XXX TODO Support any culture-specific number notation.
                n = Double.Parse(Console.ReadLine());
                break;
            }
            catch
            {
            }
        }

        Console.WriteLine($"ABS({n}) -> Math.Abs({n}) -> {Math.Abs(n)}");
        Console.WriteLine($"ATN({n}) -> Math.Atan({n}) -> {Math.Atan(n)}");
        Console.WriteLine($"COS({n}) -> Math.Cos({n}) -> {Math.Cos(n)}");
        Console.WriteLine($"EXP({n}) -> Math.Exp({n}) -> {Math.Exp(n)}");
        Console.WriteLine($"INT({n}) -> (int) {n}) -> {(int) n}");
        Console.WriteLine($"LOG({n}) -> Math.Log({n}, Math.E) -> {Math.Log(n, Math.E)}");
        Console.WriteLine($"SGN({n}) -> Math.Sign({n}) -> {Math.Sign(n)}");
        Console.WriteLine($"SQR({n}) -> Math.Sqrt({n}) -> {Math.Sqrt(n)}");
        Console.WriteLine($"TAN({n}) -> Math.Tan({n}) -> {Math.Tan(n)}");
    }
}

Mugwump

// 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
//  - http://vintage-basic.net/bcg/mugwump.bas

// This version in C#:
//  Copyright (c) 2024, Marcos Cruz (programandala.net)
//  SPDX-License-Identifier: Fair
//
// Written on 2024-12-25.
//
// Last modified: 20251205T1542+0100.

using System;
using System.Linq;

class MugwumpGame
{
    const int GRID_SIZE = 10;
    const int TURNS = 10;
    const int MUGWUMPS = 4;

    class Mugwump
    {
        internal int x = 0;
        internal int y = 0;
        internal bool hidden = false;
    }

    static Mugwump[] mugwump = new Mugwump[MUGWUMPS];
    static int found; // counter

    static string GetString(string prompt)
    {
        Console.Write(prompt);
        return Console.ReadLine();
    }

    // Print the given prompt, wait until the user enters a valid integer and
    // return it.
    //
    static int GetNumber(string prompt)
    {
        int n = 0;

        while (true)
        {
            try
            {
                n = Int32.Parse(GetString(prompt));
                break;
            }
            catch
            {
            }
        }

        return n;
    }

    // Return `true` if the given string is "yes" or a synonym.
    //
    static bool IsYes(string s)
    {
        string[] validOptions = {"ok", "y", "yeah", "yes"};
        return validOptions.Contains(s.ToLower());
    }

    // Return `true` if the given string is "no" or a synonym.
    //
    static bool IsNo(string s)
    {
        string[] validOptions = {"n", "no", "nope"};
        return validOptions.Contains(s.ToLower());
    }

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

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

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

    static void InitMugwumps()
    {
        for (int m = 0; m < MUGWUMPS; m++)
        {
            mugwump[m] = new Mugwump();
        }
    }

    // Init the mugwumps' positions, `hidden` flags and count.
    //
    static void HideMugwumps()
    {
        Random rand = new Random();

        for (int m = 0; m < MUGWUMPS; m++)
        {
            mugwump[m].x = rand.Next(GRID_SIZE);
            mugwump[m].y = rand.Next(GRID_SIZE);
            mugwump[m].hidden = true;
        }
        found = 0; // counter
    }

    // Print the given prompt, wait until the user enters a valid coord and return
    // it.
    //
    static int GetCoord(string prompt)
    {
        int coord = 0;
        while (true)
        {
            coord = GetNumber(prompt);
            if (coord < 0 || coord >= GRID_SIZE)
            {
                Console.WriteLine($"Invalid value {coord}: not in range [0, {GRID_SIZE - 1}].");
            }
            else
            {
                break;
            }
        }
        return coord;
    }

    // Return `true` if the given mugwump is hidden in the given coords.
    //
    static bool IsHere(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.
    //
    static int Distance(int m, int x, int y)
    {
        return (int) Math.Sqrt
            (
                Math.Pow((double) (mugwump[m].x - x), 2) +
                Math.Pow((double) (mugwump[m].y - y), 2)
            );
    }

    static string Plural(int n, string plural = "s", string singular = "")
    {
        return n > 1 ? plural : singular;
    }

    // Run the game.
    //
    static void Play()
    {
        int turn = 1; // counter
        InitMugwumps();
        while (true) {; // game
            Console.Clear();
            HideMugwumps();
            while (turn <= TURNS)
            {
                Console.WriteLine($"Turn number {turn}\n");
                Console.WriteLine($"What is your guess (in range [0, {GRID_SIZE - 1}])?");
                int x = GetCoord("Distance right of homebase (x-axis): ");
                int y = GetCoord("Distance above homebase (y-axis): ");
                Console.WriteLine($"\nYour guess is ({x}, {y}).");
                for (int m = 0; m < MUGWUMPS; m++)
                {
                    if (IsHere(m, x, y))
                    {
                        mugwump[m].hidden = false;
                        found++;
                        Console.WriteLine($"You have found mugwump {m}!");
                        if (found == MUGWUMPS)
                        {
                            goto endTurns;
                        }
                    }
                }
                for (int m = 0; m < MUGWUMPS; m++)
                {
                    if (mugwump[m].hidden)
                    {
                        Console.WriteLine($"You are {Distance(m, x, y)} units from mugwump {m}.");
                    }
                }
                Console.WriteLine();
                turn++;
            }; // turns
            endTurns:
            if (found == MUGWUMPS)
            {
                Console.WriteLine($"\nYou got them all in {turn} turn{Plural(turn)}!\n");
                Console.WriteLine("That was fun! let's play again…");
                Console.WriteLine("Four more mugwumps are now in hiding.");
            }
            else
            {
                Console.WriteLine($"\nSorry, that's {TURNS} tr{Plural(TURNS, "ies", "y")}.\n");
                Console.WriteLine("Here is where they're hiding:");
                for (int m = 0; m < MUGWUMPS; m++)
                {
                    if (mugwump[m].hidden)
                    {
                        Console.WriteLine($"Mugwump {m} is at ({mugwump[m].x}, {mugwump[m].y}).");
                    }
                }
            }
            Console.WriteLine();
            if (!Yes("Do you want to play again? "))
            {
                break;
            }
        }; // game
    }

    static void Main()
    {
        PrintCredits();
        PrintInstructions();
        Play();
    }
}

Name

// Name

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

// This version in C#:
//  Copyright (c) 2024, Marcos Cruz (programandala.net)
//  SPDX-License-Identifier: Fair
//
// Written on 2024-12-21.
//
// Last modified: 20251205T1543+0100.

using System;

class Name
{
    static void Main()
    {
        Console.Write("What is your name? ");
        string name = Console.ReadLine();

        double number;

        while (true)
        {
            Console.Write("Enter a number: ");
            try
            {
                number = Int64.Parse(Console.ReadLine());
                break;
            }
            catch
            {
                Console.WriteLine("Integer expected.");
            }
        }
        for (int i = 0; i < number; i++)
        {
            Console.WriteLine($"Hello, {name}!");
        }
    }
}

Poetry

// Poetry

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

// This improved remake in C#:
//  Copyright (c) 2024, Marcos Cruz (programandala.net)
//  SPDX-License-Identifier: Fair
//
// Written in 2024-12-24/25.
//
// Last modified: 20251205T1545+0100.

using System;
using System.Threading;

class poetry
{
    // Globals {{{1
    // =============================================================

    const ConsoleColor DEFAULT_COLOR = ConsoleColor.White;
    const ConsoleColor INPUT_COLOR = ConsoleColor.Green;
    const ConsoleColor TITLE_COLOR = ConsoleColor.Red;

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

    // Print the given prompt and wait until the user enters a string.
    //
    static string InputString(string prompt = "")
    {
        Console.ForegroundColor = INPUT_COLOR;
        Console.Write(prompt);
        string result = Console.ReadLine();
        Console.ForegroundColor = DEFAULT_COLOR;
        return result;
    }

    // Print the given prompt and wait until the user presses Enter.
    //
    static void PressEnter(string prompt)
    {
        InputString(prompt);
    }

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

    // Print the title at the current cursor position.
    //
    static void PrintTitle()
    {
        Console.ForegroundColor = TITLE_COLOR;
        Console.WriteLine("Poetry");
        Console.ForegroundColor = DEFAULT_COLOR;
    }

    // Print the credits at the current cursor position.
    //
    static void PrintCredits()
    {
        PrintTitle();
        Console.WriteLine("\nOriginal version in BASIC:");
        Console.WriteLine("    Unknown author.");
        Console.WriteLine("    Published in \"BASIC Computer Games\",");
        Console.WriteLine("    Creative Computing (Morristown, New Jersey, USA), 1978.\n");

        Console.WriteLine("This improved remake in C#:");
        Console.WriteLine("    Copyright (c) 2024, Marcos Cruz (programandala.net)");
        Console.WriteLine("    SPDX-License-Identifier: Fair");
    }

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

    // Is the given integer even?
    //
    static bool IsEven(int n)
    {
        return (n % 2) == 0;
    }

    static void Play()
    {
        const int MAX_PHRASES_AND_VERSES = 20;

        // counters:
        int action = 0;
        int phrase = 0;
        int phrasesAndVerses = 0;
        int verseChunks = 0;

        while (true)
        {
            verse:

            bool manageTheVerseContinuation = true;
            bool maybeAddComma = true;

            switch (action)
            {
                case 0:
                case 1:
                    switch (phrase)
                    {
                        case 0: Console.Write("MIDNIGHT DREARY"); break;
                        case 1: Console.Write("FIERY EYES"); break;
                        case 2: Console.Write("BIRD OR FIEND"); break;
                        case 3: Console.Write("THING OF EVIL"); break;
                        case 4: Console.Write("PROPHET"); break;
                    }
                    break;
                case 2:
                    switch (phrase)
                    {
                        case 0:
                            Console.Write("BEGUILING ME");
                            verseChunks = 2;
                            break;
                        case 1:
                            Console.Write("THRILLED ME");
                            break;
                        case 2:
                            Console.Write("STILL SITTING…");
                            maybeAddComma = false;
                            break;
                        case 3:
                            Console.Write("NEVER FLITTING");
                            verseChunks = 2;
                            break;
                        case 4:
                            Console.Write("BURNED");
                            break;
                    }
                    break;
                case 3:
                    switch (phrase)
                    {
                        case 0:
                            Console.Write("AND MY SOUL");
                            break;
                        case 1:
                            Console.Write("DARKNESS THERE");
                            break;
                        case 2:
                            Console.Write("SHALL BE LIFTED");
                            break;
                        case 3:
                            Console.Write("QUOTH THE RAVEN");
                            break;
                        case 4:
                            if (verseChunks != 0)
                            {
                                Console.Write("SIGN OF PARTING");
                            }
                            break;
                    }
                    break;
                case 4:
                    switch (phrase)
                    {
                        case 0: Console.Write("NOTHING MORE"); break;
                        case 1: Console.Write("YET AGAIN"); break;
                        case 2: Console.Write("SLOWLY CREEPING"); break;
                        case 3: Console.Write("…EVERMORE"); break;
                        case 4: Console.Write("NEVERMORE"); break;
                    }
                    break;
                case 5:
                    action = 0;
                    Console.WriteLine();
                    if (phrasesAndVerses > MAX_PHRASES_AND_VERSES)
                    {
                        Console.WriteLine();
                        verseChunks = 0;
                        phrasesAndVerses = 0;
                        action = 2;
                        goto verse;
                    }
                    else
                    {
                        manageTheVerseContinuation = false;
                    }
                    break;
            }

            Random rand = new Random();

            if (manageTheVerseContinuation)
            {
                Thread.Sleep(250); // milliseconds

                if (maybeAddComma && ! (verseChunks == 0 || rand.NextDouble() > 0.19))
                {
                    Console.Write(",");
                    verseChunks = 2;
                }

                if (rand.NextDouble() > 0.65)
                {
                    Console.WriteLine();
                    verseChunks = 0;
                }
                else
                {
                    Console.Write(" ");
                    verseChunks += 1;
                }
            }

            action += 1;
            phrase = rand.Next(5);
            phrasesAndVerses += 1;

            if (! (verseChunks > 0 || IsEven(action)))
            {
                Console.Write("     ");
            }
        }
        // verse loop
    }

    static void Main()
    {
        Console.Clear();
        PrintCredits();
        PressEnter("\nPress the Enter key to start. ");
        Console.Clear();
        Play();
    }
}

Russian Roulette

// Russian Roulette

// Original version in BASIC:
//  By Tom Adametx, 1978.
//  Creative Computing's BASIC Games.
//  - https://www.atariarchives.org/basicgames/showpage.php?page=141
//  - http://vintage-basic.net/games.html
//  - http://vintage-basic.net/bcg/russianroulette.bas
//  - http://www.retroarchive.org/cpm/games/ccgames.zip

// This version in C#:
//  Copyright (c) 2024, Marcos Cruz (programandala.net)
//  SPDX-License-Identifier: Fair
//
// Written on 2024-12-21.
//
// Last modified: 20251205T1547+0100.

using System;

class RussianRoulette
{
    static void PressEnterToStart()
    {
        Console.Write("Press Enter to start. ");
        Console.ReadKey();
    }

    static void PrintCredits()
    {
        Console.Clear();
        Console.WriteLine("Russian Roulette\n");
        Console.WriteLine("Original version in BASIC:");
        Console.WriteLine("    Creative Computing (Morristown, New Jersey, USA), ca. 1980.\n");
        Console.WriteLine("This version in C#:");
        Console.WriteLine("    Copyright (c) 2024, Marcos Cruz (programandala.net)");
        Console.WriteLine("    SPDX-License-Identifier: Fair\n");
        PressEnterToStart();
    }

    static void PrintInstructions()
    {
        Console.Clear();
        Console.WriteLine("Here is a revolver.");
        Console.WriteLine("Type 'f' to spin chamber and pull trigger.");
        Console.WriteLine("Type 'g' to give up, and play again.");
        Console.WriteLine("Type 'q' to quit.\n");
    }

    static void Play()
    {
        Random rand = new Random();

        int times;

        while (true) { // game loop
            PrintInstructions();
            times = 0;
            bool playing = true;
            while (playing)
            {
                Console.Write("> ");
                switch (Console.ReadLine())
                {
                    case "f" : // fire
                        if (rand.Next(100) > 83)
                        {
                            Console.WriteLine("Bang! You're dead!");
                            Console.WriteLine("Condolences will be sent to your relatives.");
                            playing = false;
                        }
                        else
                        {
                            times += 1;
                            if (times > 10)
                            {
                                Console.WriteLine("You win!");
                                Console.WriteLine("Let someone else blow his brains out.");
                                playing = false;
                            }
                            else
                            {
                                Console.WriteLine("Click.");
                            }
                        }
                        break;
                    case "g" :; // give up
                        Console.WriteLine("Chicken!");
                        playing = false; // force exit
                        break;
                    case "q" :; // quit
                        return;
                }
            }; // play loop
            PressEnterToStart();
        }; // game loop
    }

    static void Main()
    {
        PrintCredits();
        Play();
        Console.WriteLine("Bye!");
    }
}

Seance

// Seance

// Original version in BASIC:
//  By Chris Oxlade, 1983.
//  Creepy Computer Games (Usborne Publishing Ltd.)
//  - https://archive.org/details/seance.qb64
//  - https://github.com/chaosotter/basic-games

// This version in C#:
//  Copyright (c) 2024, Marcos Cruz (programandala.net)
//  SPDX-License-Identifier: Fair
//
// Written on 2024-12-25.
//
// Last modified: 20251205T1547+0100.

using System;
using System.Threading;

class Seance
{
    const int MAX_SCORE = 50;

    const int MAX_MESSAGE_LENGTH = 6;
    const int MIN_MESSAGE_LENGTH = 3;

    const int BASE_CHARACTER_CODE = (int) '@';
    const char PLANCHETTE = '*';

    const int FIRST_LETTER_NUMBER = 1;
    const int LAST_LETTER_NUMBER = 26;

    const ConsoleColor BOARD_COLOR = ConsoleColor.Cyan;
    const ConsoleColor DEFAULT_COLOR = ConsoleColor.White;
    const ConsoleColor INPUT_COLOR = ConsoleColor.Green;
    const ConsoleColor INSTRUCTIONS_COLOR = ConsoleColor.DarkYellow;
    const ConsoleColor MISTAKE_EFFECT_COLOR = ConsoleColor.Red;
    const ConsoleColor PLANCHETTE_COLOR = ConsoleColor.DarkYellow;
    const ConsoleColor TITLE_COLOR = ConsoleColor.Red;

    const int INPUT_X = BOARD_X;
    const int INPUT_Y = BOARD_Y + BOARD_BOTTOM_Y + 4;

    const int MESSAGES_Y = INPUT_Y;

    const int MISTAKE_EFFECT_PAUSE = 3; // seconds

    const int BOARD_ACTUAL_WIDTH = BOARD_WIDTH + 2 * BOARD_PAD; // screen columns
    const int BOARD_BOTTOM_Y = BOARD_HEIGHT + 1; // relative to the board
    const int BOARD_HEIGHT = 5; // characters displayed on the left and right borders
    const int BOARD_PAD = 1; // blank characters separating the board from its left and right borders
    const int BOARD_WIDTH = 8; // characters displayed on the top and bottom borders
    const int BOARD_X = 29; // screen column
    const int BOARD_Y = 5; // screen line

    // Print the given prompt and wait until the user enters a string.
    //
    static string Input(string prompt = "")
    {
        Console.ForegroundColor = INPUT_COLOR;
        Console.Write(prompt);
        string result = Console.ReadLine();
        Console.ForegroundColor = DEFAULT_COLOR;
        return result;
    }

    // Print the given prompt and wait until the user presses Enter.
    //
    static void PressEnter(string prompt)
    {
        Input(prompt);
    }

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

    // Print the given text on the given row, centered on the board.
    //
    static void PrintBoardCentered(string text, int y)
    {
        Console.SetCursorPosition(boardCenteredX(text), y);
        Console.WriteLine(text);
    }

    const string TITLE = "Seance";

    // Print the title at the current cursor position.
    //
    static void PrintTitle()
    {
        Console.ForegroundColor = TITLE_COLOR;
        Console.WriteLine(TITLE);
        Console.ForegroundColor = DEFAULT_COLOR;
    }

    // Print the title on the given row, centered on the board.
    //
    static void PrintBoardCenteredTitle(int y)
    {
        Console.ForegroundColor = TITLE_COLOR;
        PrintBoardCentered(TITLE, y);
        Console.ForegroundColor = DEFAULT_COLOR;
    }

    static void PrintCredits()
    {
        PrintTitle();
        Console.WriteLine("\nOriginal version in BASIC:");
        Console.WriteLine("    Written by Chris Oxlade, 1983.");
        Console.WriteLine("    https://archive.org/details/seance.qb64");
        Console.WriteLine("    https://github.com/chaosotter/basic-games");
        Console.WriteLine("\nThis version in C#:");
        Console.WriteLine("    Copyright (c) 2024, Marcos Cruz (programandala.net)");
        Console.WriteLine("    SPDX-License-Identifier: Fair");
    }

    static void PrintInstructions()
    {
        PrintTitle();
        Console.ForegroundColor = INSTRUCTIONS_COLOR;
        Console.WriteLine("\nMessages from the spirits are coming through, letter by letter.  They want you");
        Console.WriteLine("to remember the letters and type them into the computer in the correct order.");
        Console.WriteLine("If you make mistakes, they will be angry -- very angry...");
        Console.WriteLine();
        Console.WriteLine("Watch for stars on your screen -- they show the letters in the spirits'");
        Console.WriteLine("messages.");
        Console.ForegroundColor = DEFAULT_COLOR;
    }

    // Print the given letter at the given board coordinates.
    //
    static void PrintCharacter(int y, int x, char a)
    {
        Console.SetCursorPosition(x + BOARD_X, y + BOARD_Y);
        Console.Write(a);
    }

    static void PrintBoard()
    {
        Console.ForegroundColor = BOARD_COLOR;
        for (int i = 1; i <= BOARD_WIDTH; i++)
        {
            PrintCharacter(0, i + 1, (char) (BASE_CHARACTER_CODE + i)); // top border
            PrintCharacter(BOARD_BOTTOM_Y, i + 1, (char) (BASE_CHARACTER_CODE + LAST_LETTER_NUMBER - BOARD_HEIGHT - i + 1)); // bottom border
        }
        for (int i = 1; i <= BOARD_HEIGHT; i++)
        {
            PrintCharacter(i , 0, (char) (BASE_CHARACTER_CODE + LAST_LETTER_NUMBER - i + 1)); // left border
            PrintCharacter(i , 3 + BOARD_WIDTH, (char) (BASE_CHARACTER_CODE + BOARD_WIDTH + i)); // right border
        }
        Console.WriteLine();
        Console.ForegroundColor = DEFAULT_COLOR;
    }

    // Return a random integer in the given inclusive range.
    //
    static int RandomInInclusiveRange(int min, int max)
    {
        Random rand = new Random();
        return rand.Next(max - min + 1) + min;
    }

    // Print the given mistake effect, wait a configured number of seconds and
    // finally erase it.
    //
    static void PrintMistakeEffect(string effect)
    {
        int x = boardCenteredX(effect);

        Console.CursorVisible = false;

        Console.SetCursorPosition(x, MESSAGES_Y);
        Console.ForegroundColor = MISTAKE_EFFECT_COLOR;
        Console.WriteLine(effect);

        Thread.Sleep(1000 * MISTAKE_EFFECT_PAUSE); // milliseconds

        Console.ForegroundColor = DEFAULT_COLOR;
        Console.SetCursorPosition(x, MESSAGES_Y);
        string spaces = new string(' ', effect.Length);
        Console.Write(spaces);

        Console.CursorVisible = true;
    }

    // Return a new message of the given length, after marking its letters on the
    // board.
    //
    static string Message(int length)
    {
        int y;
        int x;
        string message = "";
        Console.CursorVisible = false;
        for (int i = 1; i <= length; i++)
        {
            int letterNumber = RandomInInclusiveRange(FIRST_LETTER_NUMBER, LAST_LETTER_NUMBER);
            char letter = (char) (BASE_CHARACTER_CODE + letterNumber);
            message = $"{message}{letter}";
            if (letterNumber <= BOARD_WIDTH)
            {
                // top border
                y = 1;
                x = letterNumber + 1;
            }
            else if (letterNumber <= BOARD_WIDTH + BOARD_HEIGHT)
            {
                // right border
                y = letterNumber - BOARD_WIDTH;
                x = 2 + BOARD_WIDTH;
            }
            else if (letterNumber <= BOARD_WIDTH + BOARD_HEIGHT + BOARD_WIDTH)
            {
                // bottom border
                y = BOARD_BOTTOM_Y - 1;
                x = 2 + BOARD_WIDTH + BOARD_HEIGHT + BOARD_WIDTH - letterNumber;
            }
            else
            {
                // left border
                y = 1 + LAST_LETTER_NUMBER - letterNumber;
                x = 1;
            }
            Console.ForegroundColor = PLANCHETTE_COLOR;
            PrintCharacter(y, x, PLANCHETTE);
            Console.ForegroundColor = DEFAULT_COLOR;
            Thread.Sleep(1000); // milliseconds
            PrintCharacter(y, x, ' ');
        }
        Console.CursorVisible = true;
        return message;
    }

    // Accept a string from the user, erase it from the screen and return it.
    //
    static string MessageUnderstood()
    {
        string prompt = "? ";

        Console.SetCursorPosition(INPUT_X, INPUT_Y);
        string message = Input(prompt).ToUpper();

        string spaces = new string(' ', prompt.Length + message.Length);
        Console.SetCursorPosition(INPUT_X, INPUT_Y);
        Console.Write(spaces);

        return message;
    }

    static void Play()
    {
        int score = 0;
        int mistakes = 0;
        PrintBoardCenteredTitle(1);
        PrintBoard();

        while (true)
        {
            int messageLength = RandomInInclusiveRange(MIN_MESSAGE_LENGTH, MAX_MESSAGE_LENGTH);
            if (Message(messageLength) != MessageUnderstood())
            {
                mistakes++;
                switch (mistakes)
                {
                    case 1:
                        PrintMistakeEffect("The table begins to shake!");
                        break;
                    case 2:
                        PrintMistakeEffect("The light bulb shatters!");
                        break;
                    case 3:
                        PrintMistakeEffect("Oh, no!  A pair of clammy hands grasps your neck!");
                        return;
                }
            }
            else
            {
                score += messageLength;
                if (score >= MAX_SCORE)
                {
                    PrintBoardCentered("Whew!  The spirits have gone!", MESSAGES_Y);
                    PrintBoardCentered("You live to face another day!", MESSAGES_Y + 1);
                    return;
                }
            }
        }
    }

    static void Main()
    {
        Console.ForegroundColor = DEFAULT_COLOR;
        Console.Clear();
        PrintCredits();

        PressEnter("\nPress the Enter key to read the instructions. ");
        Console.Clear();
        PrintInstructions();

        PressEnter("\nPress the Enter key to start. ");
        Console.Clear();
        Play();
        Console.WriteLine("\n");
    }
}

Sine Wave

// Sine Wave

// Original version in BASIC:
//  Anonymous, 1978.
//  Creative Computing's BASIC Games.
//  - https://www.atariarchives.org/basicgames/showpage.php?page=146
//  - http://vintage-basic.net/games.html
//  - http://vintage-basic.net/bcg/sinewave.bas
//  - http://www.retroarchive.org/cpm/games/ccgames.zip

// This version in C#:
//  Copyright (c) 2024, Marcos Cruz (programandala.net)
//  SPDX-License-Identifier: Fair
//
// Written on 2024-12-20.
//
// Last modified: 20251205T1548+0100.

using System;

class SineWave
{
    static string[] word = {"", ""};

    // Ask the user to enter two words and store them into the `word` array.
    //
    static void getWords()
    {
        string[] order = {"first", "second"};

        int n = 0;
        while (n < 2)
        {
            while (word[n] == "")
            {
                Console.Write($"Enter the {order[n]} word: ");
                word[n] = Console.ReadLine();
            }
            n++;
        }
    }

    static void printCredits()
    {
        Console.WriteLine("Sine Wave\n");
        Console.WriteLine("Original version in BASIC:");
        Console.WriteLine("    Creative Computing (Morristown, New Jersey, USA), ca. 1980.\n");
        Console.WriteLine("This version in C#:");
        Console.WriteLine("    Copyright (c) 2024, Marcos Cruz (programandala.net)");
        Console.WriteLine("    SPDX-License-Identifier: Fair\n");
        Console.Write("Press Enter to start. ");
        Console.ReadKey();
    }

    static void draw()
    {
        bool even = false;
        double angle = 0.0;

        while (angle <= 40.0)
        {
            int i = 0;
            while (i < (int) (26 + 25 * Math.Sin(angle)))
            {
                Console.Write(" ");
                i++;
            }
            Console.WriteLine(word[even ? 1 : 0]);
            even = ! even;
            angle += 0.25;
        }
    }

    static void Main()
    {
        Console.Clear();
        printCredits();
        Console.Clear();
        getWords();
        Console.Clear();
        draw();
    }
}

Slots

// Slots
// A slot machine simulation.

// Original version in BASIC:
//  By Fred Mirabelle and Bob Harper, 1973-01-29.
//  Creative Computing's BASIC Games.
//  - https://www.atariarchives.org/basicgames/showpage.php?page=149
//  - http://vintage-basic.net/games.html
//  - http://vintage-basic.net/bcg/slots.bas

// This version in C#:
//  Copyright (c) 2024, Marcos Cruz (programandala.net)
//  SPDX-License-Identifier: Fair
//
// Written in 2024-12-22/24.
//
// Last modified: 20251205T1549+0100.

using System;
using System.Diagnostics;

class Slots
{
    static string[] image = {" BAR  ", " BELL ", "ORANGE", "LEMON ", " PLUM ", "CHERRY"};
    const int BAR = 0; // position of "BAR" in `image`.
    static ConsoleColor[] color =
    {
        ConsoleColor.White,
        ConsoleColor.DarkCyan,
        ConsoleColor.DarkYellow,
        ConsoleColor.Yellow,
        ConsoleColor.White,
        ConsoleColor.Red };
    const int MAX_BET = 100;
    const int MIN_BET = 1;

    static void PressEnter(string prompt)
    {
        Console.Write(prompt);
        Console.ReadLine();
    }

    static void PrintCredits()
    {
        Console.Clear();
        Console.WriteLine("Slots");
        Console.WriteLine("A slot machine simulation.\n");
        Console.WriteLine("Original version in BASIC:");
        Console.WriteLine("    Creative computing (Morristown, New Jersey, USA).");
        Console.WriteLine("    Produced by Fred Mirabelle and Bob Harper on 1973-01-29.\n");
        Console.WriteLine("This version in C#:");
        Console.WriteLine("    Copyright (c) 2024, Marcos Cruz (programandala.net)");
        Console.WriteLine("    SPDX-License-Identifier: Fair\n");
        PressEnter("Press Enter for instructions.");
    }

    static void PrintInstructions()
    {
        Console.Clear();
        Console.WriteLine("You are in the H&M casino, in front of one of our");
        Console.WriteLine($"one-arm bandits. Bet from {MIN_BET} to {MAX_BET} USD (or 0 to quit).\n");
        PressEnter("Press Enter to start.");
    }

    static int Won(int prize, int bet)
    {
        switch (prize)
        {
            case   2: Console.WriteLine("DOUBLE!"); break;
            case   5: Console.WriteLine("*DOUBLE BAR*"); break;
            case  10: Console.WriteLine("**TOP DOLLAR**"); break;
            case 100: Console.WriteLine("***JACKPOT***"); break;
        }
        Console.WriteLine("You won!");
        return (prize + 1) * bet;
    }

    static void ShowStandings(int usd)
    {
        Console.WriteLine($"Your standings are {usd} USD.");
    }

    static void PrintReels(int[] reel)
    {
        ConsoleColor currentBackgroundColor = Console.BackgroundColor;
        ConsoleColor currentForegroundColor = Console.ForegroundColor;
        Console.SetCursorPosition(0, 0);
        foreach (int r in reel)
        {
            Console.ForegroundColor = color[r];
            Console.Write($"[{image[r]}] ");
        }
        Console.BackgroundColor = currentBackgroundColor;
        Console.ForegroundColor = currentForegroundColor;
        Console.WriteLine("");
    }

    static void InitReels(ref int[] reel)
    {
        Random rand = new Random();
        int images = image.Length;
        for (int i = 0; i < reel.Length; i++)
        {
            reel[i] = rand.Next(images);
        }
    }

    static void SpinReels(ref int[] reel)
    {
        const int MILLISECONDS = 2000;
        Console.CursorVisible = false;
        Stopwatch timer = new Stopwatch();
        timer.Start();
        while(timer.ElapsedMilliseconds < MILLISECONDS)
        {
            InitReels(ref reel);
            PrintReels(reel);
        }
        Console.CursorVisible = true;
    }

    // Return the number of equals and bars in the given array.
    //
    static (int, int) Prize(int[] reel)
    {
        int equals = 0;
        int bars = 0;

        for (int i = 0; i < reel.Length; i++)
        {
            for (int j = i + 1; j < reel.Length; j++)
            {
                equals +=  Convert.ToInt32(reel[i] == reel[j]);
            }
        }
        if (equals > 0 && equals < reel.Length)
        {
            equals++;
        }

        foreach (int i in reel)
        {
            bars += Convert.ToInt32(i == BAR);
        }
        return (equals, bars);
    }

    static string GetString(string prompt)
    {
        Console.Write(prompt);
        return Console.ReadLine();
    }

    static int GetInteger(string prompt)
    {
        int n = 0;

        while (true)
        {
            try
            {
                n = Int32.Parse(GetString(prompt));
                break;
            }
            catch { }
        }

        return n;
    }

    static void Play()
    {
        int standings = 0;
        int bet = 0;
        int[] reel = {0, 0, 0};
        int equals = 0;
        int bars = 0;

        InitReels(ref reel);

        while (true) { // play loop

            while (true) { // bet loop
                Console.Clear();
                PrintReels(reel);
                bet = GetInteger("Your bet (or 0 to quit): ");
                if (bet > MAX_BET)
                {
                    Console.WriteLine($"House limits are {MAX_BET} USD.");
                    PressEnter("Press Enter to try again.");
                }
                else if (bet < MIN_BET)
                {
                    Console.WriteLine("Type \"q\" to confirm you want to quit.");
                    string confirm = Console.ReadLine().ToLower();
                    if (confirm == "q")
                    {
                        goto showStandings;
                    }
                }
                else
                {
                    break; // bet loop
                };
            };

            Console.Clear();
            SpinReels(ref reel);
            (equals, bars) = Prize(reel);

            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:
                    Console.WriteLine("You lost.");
                    standings -= bet;
                    break;
            };

            ShowStandings(standings);
            PressEnter("Press Enter to continue.");
        }; // play loop

        showStandings:

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

    static void Main()
    {
        PrintCredits();
        PrintInstructions();
        Play();
    }
}

Stars

// Stars

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

// This version in C#:
//  Copyright (c) 2024, Marcos Cruz (programandala.net)
//  SPDX-License-Identifier: Fair
//
// Written on 2024-12-21.
//
// Last modified: 20251205T1549+0100.

using System;
using System.Linq;

class Stars
{
    static void Main()
    {
        Console.Write("What is your name? ");
        string name = Console.ReadLine();
        Console.WriteLine($"Hello, {name}.");

        string answer;
        string[] afirmativeAnswers = {"ok", "yeah", "yes", "y"};

        do
        {
            double number;

            while (true)
            {
                Console.Write("Enter a number: ");
                try
                {
                    number = Int64.Parse(Console.ReadLine());
                    break;
                }
                catch
                {
                    Console.WriteLine("Integer expected.");
                }
            }

            for (int i = 0; i < number; i++)
            {
                Console.Write("*");
            }
            Console.WriteLine();

            Console.Write("Do you want more stars? ");
            answer = Console.ReadLine().ToLower();
        }
        while (afirmativeAnswers.Contains(answer));
    }
}

Strings

// Strings

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

// This version in C#:
//  Copyright (c) 2024, Marcos Cruz (programandala.net)
//  SPDX-License-Identifier: Fair
//
// Written in 2024-12-21/25.
//
// Last modified: 20251205T1549+0100.

using System;

class vintageBasicStrings
{
    static string GetString(string prompt)
    {
        Console.Write(prompt);
        return Console.ReadLine();
    }

    static int GetInteger(string prompt)
    {
        int n = 0;

        while (true)
        {
            try
            {
                n = Int32.Parse(GetString(prompt));
                break;
            }
            catch
            {
            }
        }

        return n;
    }

    static void Main()
    {
        string s = GetString("Enter a string: ");
        int n = GetInteger("Enter an integer: ");

        Console.WriteLine();

        Console.Write($"ASC(\"{s}\") --> ");
        Console.Write($"(int) \"{s}\"[0] --> ");
        Console.WriteLine((int) s[0]);

        Console.Write($"CHR$({n}) --> ");
        Console.Write($"(char) ({n}) --> ");
        Console.WriteLine("'" + (char) n + "'");

        Console.Write($"LEFT$(\"{s}\", {n}) --> ");
        Console.Write($"\"{s}\".Substring(0, Math.Min({n}, \"{s}\".Length) --> ");
        Console.WriteLine("\"" + s.Substring(0, Math.Min(n, s.Length)) + "\"");

        Console.Write($"MID$(\"{s}\", {n}) --> ");
        Console.Write($"{n} > \"{s}\".Length ? \"\" : \"{s}\".Substring({n} - 1) --> ");
        Console.WriteLine("\"" + (n > s.Length ? "" : s.Substring(n - 1)) + "\"");

        Console.Write($"MID$(\"{s}\", {n}, 3) --> ");
        Console.Write($"{n} > \"{s}\".Length ? \"\" : \"{s}\".Substring({n} - 1, Math.Min(3, \"{s}\".Length - {n} + 1)) --> ");
        Console.WriteLine("\"" + (n > s.Length ? "" : s.Substring(n - 1, Math.Min(3, s.Length - n + 1)) + "\""));

        Console.Write($"RIGHT$(\"{s}\", {n}) --> ");
        Console.Write($"\"{s}\".Substring(Math.Max(0, \"{s}\".Length - {n}) --> ");
        Console.WriteLine("\"" + s.Substring(Math.Max(0, s.Length - n)) + "\"");

        Console.Write($"LEN(\"{s}\") --> ");
        Console.Write($"\"{s}\".Length --> ");
        Console.WriteLine(s.Length);

        Console.Write($"VAL(\"{s}\") --> ");
        int v;
        try{ v = Int32.Parse(s); } catch { v = 0; };
        Console.WriteLine($"int v; try{{ v = Int32.Parse(\"{s}\"); }} catch {{ v = 0; }} --> {v}");

        Console.Write($"STR$({n}) --> ");
        Console.Write($"Convert.ToString({n}) --> ");
        Console.WriteLine("\"" + Convert.ToString(n) + "\"");

        Console.Write($"SPC({n}) --> ");
        Console.Write($"new string(' ', {n}) --> ");
        Console.WriteLine("\"" + new string(' ', n) + "\"");
    }
}

Xchange

// Xchange

// Original version in BASIC:
//  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 C#:
//  Copyright (c) 2024, Marcos Cruz (programandala.net)
//  SPDX-License-Identifier: Fair
//
// Written in 2024-12-29/2025-01-02.
//
// Last modified: 20251205T1550+0100.

using System;
using System.Linq;

class xchange
{
    // Globals {{{1
    // =============================================================

    const ConsoleColor BOARD_INK = ConsoleColor.Cyan;
    const ConsoleColor DEFAULT_INK = ConsoleColor.White;
    const ConsoleColor INPUT_INK = ConsoleColor.Green;
    const ConsoleColor INSTRUCTIONS_INK = ConsoleColor.DarkYellow;
    const ConsoleColor TITLE_INK = ConsoleColor.Red;

    const string BLANK = "*";

    const int GRID_HEIGHT = 3; // cell rows
    const int GRID_WIDTH = 3; // cell columns

    const int CELLS = GRID_WIDTH * GRID_HEIGHT;

    static string[] pristineGrid = new string[CELLS];

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

    const int MAX_PLAYERS = 4;

    static string[][] grid = new string[MAX_PLAYERS][];

    static bool[] isPlaying = new bool[MAX_PLAYERS];

    static int players;

    const string QUIT_COMMAND = "X";

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

    // Print the given prompt and wait until the user enters an integer.
    //
    static int InputInt(string prompt = "")
    {
        Console.ForegroundColor = INPUT_INK;

        int number;

        while (true)
        {
            Console.Write(prompt);
            try
            {
                number = (int) Int64.Parse(Console.ReadLine());
                break;
            }
            catch
            {
                Console.WriteLine("Integer expected.");
            }
        }
        Console.ForegroundColor = DEFAULT_INK;
        return number;
    }

    // Print the given prompt and wait until the user enters a string.
    //
    static string InputString(string prompt = "")
    {
        Console.ForegroundColor = INPUT_INK;
        Console.Write(prompt);
        string result = Console.ReadLine();
        Console.ForegroundColor = DEFAULT_INK;
        return result;
    }

    // Print the given prompt and wait until the user presses Enter.
    //
    static void PressEnter(string prompt)
    {
        InputString(prompt);
    }

    // Return `true` if the given string is "yes" or a synonym.
    //
    static bool IsYes(string s)
    {
        string[] validOptions = {"ok", "y", "yeah", "yes"};
        return validOptions.Contains(s.ToLower());
    }

    // Return `true` if the given string is "no" or a synonym.
    //
    static bool IsNo(string s)
    {
        string[] validOptions = {"n", "no", "nope"};
        return validOptions.Contains(s);
    }

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

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

    // Print the title at the current cursor position.
    //
    static void PrintTitle()
    {
        Console.ForegroundColor = TITLE_INK;
        Console.WriteLine("Xchange");
        Console.ForegroundColor = DEFAULT_INK;
    }

    // Print the credits at the current cursor position.
    //
    static void PrintCredits()
    {
        PrintTitle();
        Console.WriteLine("\nOriginal version in BASIC:");
        Console.WriteLine("    Written by Thomas C. McIntire, 1979.");
        Console.WriteLine("    Published in \"The A to Z Book of Computer Games\", 1979.");
        Console.WriteLine("    https://archive.org/details/The_A_to_Z_Book_of_Computer_Games/page/n269/mode/2up");
        Console.WriteLine("    https://github.com/chaosotter/basic-games");
        Console.WriteLine("\nThis improved remake in C#:");
        Console.WriteLine("    Copyright (c) 2024, Marcos Cruz (programandala.net)");
        Console.WriteLine("    SPDX-License-Identifier: Fair");
    }

    // Print the instructions at the current cursor position.
    //
    static void PrintInstructions()
    {
        PrintTitle();
        Console.ForegroundColor = INSTRUCTIONS_INK;
        Console.WriteLine("\nOne or two may play.  If two, you take turns.  A grid looks like this:\n");
        Console.ForegroundColor = BOARD_INK;
        Console.WriteLine("    F G D");
        Console.Write($"    A H {BLANK}\n");
        Console.WriteLine("    E B C\n");
        Console.ForegroundColor = INSTRUCTIONS_INK;
        Console.WriteLine("But it should look like this:\n");
        Console.ForegroundColor = BOARD_INK;
        Console.WriteLine("    A B C");
        Console.WriteLine("    D E F");
        Console.Write($"    G H {BLANK}\n\n");
        Console.ForegroundColor = INSTRUCTIONS_INK;
        Console.Write($"You may exchange any one letter with the '{BLANK}', but only one that's adjacent:\n");
        Console.WriteLine("above, below, left, or right.  Not all puzzles are possible, and you may enter");
        Console.Write($"'{QUIT_COMMAND}' to give up.\n\n");
        Console.WriteLine("Here we go...");
        Console.ForegroundColor = DEFAULT_INK;
    }

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

    // Print the given player's grid title.
    //
    static void PrintGridTitle(int player)
    {
        Console.SetCursorPosition(GRIDS_COLUMN + (player * GRIDS_GAP), GRIDS_ROW);
        Console.Write($"Player {player + 1}");
    }

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

    // Return the cursor position of the given player's grid prompt.
    //
    static (int row, int column) GridPromptPosition(int player)
    {
        int gridRow = CELLS / GRID_HEIGHT;
        int gridColumn = CELLS % GRID_WIDTH;
        int titleMargin = players > 1 ? 2 : 0;
        return (GRIDS_ROW + titleMargin + gridRow + 1, GRIDS_COLUMN + (gridColumn * CELLS_GAP) + (player * GRIDS_GAP));
    }

    // Print the given player's grid, in the given or default color.
    //
    static void PrintGrid(int player, ConsoleColor color = BOARD_INK)
    {
        if (players > 1)
        {
            PrintGridTitle(player);
        }
        Console.ForegroundColor = color;
        for (int cell = 0; cell < CELLS; cell++)
        {
            (int y, int x) = CellPosition(player, cell);
            Console.SetCursorPosition(x, y);
            Console.Write(grid[player][cell]);
        }
        Console.ForegroundColor = DEFAULT_INK;
    }

    // Print the current players' grids.
    //
    static void PrintGrids()
    {
        for (int player = 0; player < players; player++)
        {
            if (isPlaying[player])
            {
                PrintGrid(player);
            }
        }
        Console.WriteLine();
        // EraseScreenDown(); // XXX TODO
    }

    // Scramble the grid of the given player.
    //
    static void ScrambleGrid(int player)
    {
        Random rand = new Random();
        for (int cell = 0; cell < CELLS; cell++)
        {
            int randomCell = rand.Next(CELLS);
            // Exchange the contents of the current cell with that of the random one.
            string tmp = grid[player][cell];
            grid[player][cell] = grid[player][randomCell];
            grid[player][randomCell] = tmp;
        }
    }

    // Init the grids.
    //
    static void InitGrids()
    {
        grid[0] = (string[]) pristineGrid.Clone();
        ScrambleGrid(0);
        for (int player = 0 + 1; player < players; player++)
        {
            grid[player] = (string[]) grid[0].Clone();
        }
    }

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

    // Return a message prefix for the given player.
    //
    static string PlayerPrefix(int player)
    {
        return players > 1 ? $"Player {player + 1}: " : "";
    }

    // Return the cursor position of the given player's messages, adding the given
    // row increment, which defaults to zero.
    //
    static (int row, int column) MessagePosition(int player, int rowInc = 0)
    {
        (int promptRow, _) = GridPromptPosition(player);
        return (promptRow + 2 + rowInc, 1);
    }

    // Erase the current line to the right from the position of the cursor.
    //
    static void EraseLineRight()
    {
        int y = Console.CursorTop;
        int x = Console.CursorLeft;
        string blank = new String(' ', Console.WindowWidth - x - 1);

        Console.Write(blank);
        Console.SetCursorPosition(x, y);
    }

    // Print the given message about the given player, adding the given row
    // increment, which defaults to zero, to the default cursor coordinates.
    //
    static void PrintMessage(string message, int player, int rowInc = 0)
    {
        (int y, int x) = MessagePosition(player, rowInc);
        Console.SetCursorPosition(x, y);
        Console.Write($"{PlayerPrefix(player)}{message}");
        EraseLineRight();
        Console.WriteLine();
    }

    // Erase the last message about the given player.
    //
    static void EraseMessage(int player)
    {
        (int y, int x) = MessagePosition(player);
        Console.SetCursorPosition(x, y);
        EraseLineRight();
    }

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

    // Return a message with the players range.
    //
    static string PlayersRangeMessage()
    {
        return (MAX_PLAYERS == 2) ? "1 or 2" : $"from 1 to {MAX_PLAYERS}";
    }

    // Return the number of players, asking the user if needed.
    //
    static int NumberOfPlayers()
    {
        int players = 0;
        PrintTitle();
        Console.WriteLine();
        while (players < 1 || players > MAX_PLAYERS)
        {
            players = InputInt($"Number of players ({PlayersRangeMessage()}): ");
        }
        return players;
    }

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

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

    // Are the given cells adjacent?
    //
    static bool AreCellsAdjacent(int cell_1, int cell_2)
    {
        if (cell_2 == cell_1 + 1 && ! isFirstCellOfA_gridRow(cell_2))
            return true;
        else if (cell_2 == cell_1 + GRID_WIDTH)
            return true;
        else if (cell_2 == cell_1 - 1  && ! isLastCellOfA_gridRow(cell_2))
            return true;
        else if (cell_2 == cell_1 - GRID_WIDTH)
            return true;
        else
            return false;
    }

    // Is the given player's character cell a valid move, i.e. is it adjacent to
    // the blank cell? If so, return the blank cell of the grid and `true`
    // otherwise return a fake cell and `false`.
    //
    static (int blankCell, bool ok) IsLegalMove(int player, int charCell)
    {
        const int NOWHERE = -1;

        for (int cell = 0; cell < CELLS; cell++)
        {
            if (grid[player][cell] == BLANK)
            {
                if (AreCellsAdjacent(charCell, cell))
                {
                    return (cell, true);
                }
                break;
            }
        }

        PrintMessage($"Illegal move \"{grid[player][charCell]}\".", player);
        return (NOWHERE, false);
    }

    // Is the given player's command valid, i.e. a grid character? If so, return
    // its position in the grid and `true`; otherwise print an error message and
    // return a fake position and `false`.
    //
    static (int position, bool ok) IsValidCommand(int player, string command)
    {
        // XXX FIXME

        const int NOWHERE = -1;
        if (command != BLANK)
        {
            for (int i = 0; i < CELLS; i++)
            {
                if (grid[player][i] == command)
                {
                    return (i, true);
                }
            }
        }
        PrintMessage($"Invalid character \"{command}\".", player);
        return (NOWHERE, false);
    }

    // Forget the given player, who quitted.
    //
    static void ForgetPlayer(int player)
    {
        isPlaying[player] = false;
        PrintGrid(player, DEFAULT_INK);
    }

    // Play the turn of the given player.
    //
    static void PlayTurn(int player)
    {
        int blankPosition;
        int characterPosition = 0;

        if (isPlaying[player])
        {
            while (true)
            {
                string command;
                bool ok = false;
                while (! ok)
                {
                    (int y, int x) = GridPromptPosition(player);
                    Console.SetCursorPosition(x, y);
                    EraseLineRight();
                    Console.SetCursorPosition(x, y);
                    command = InputString("Move: ").Trim().ToUpper();
                    if (command == QUIT_COMMAND)
                    {
                        ForgetPlayer(player);
                        return;
                    }
                    (characterPosition, ok) = IsValidCommand(player, command);
                }
                (blankPosition, ok) = IsLegalMove(player, characterPosition);
                if (ok)
                {
                    break;
                }
            }
            EraseMessage(player);
            grid[player][blankPosition] = grid[player][characterPosition];
            grid[player][characterPosition] = BLANK;
        }
    }

    // Play the turns of all players.
    //
    static void PlayTurns()
    {
        for (int player = 0; player < players; player++) PlayTurn(player);
    }

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

    // Has someone won? If so, print a message for every winner and return `true`
    // otherwise just return `false`.
    //
    static bool HasSomeoneWon()
    {
        int winners = 0;

        for (int player = 0; player < players; player++)
        {
            if (isPlaying[player])
            {
                if (grid[player].SequenceEqual(pristineGrid))
                {
                    winners += 1;
                    if (winners > 0)
                    {
                        string too = winners > 1 ? ", too" : "";
                        PrintMessage
                        (
                            $"You're the winner{too}!",
                            player,
                            winners - 1
                        );
                    }
                }
            }
        }

        return winners > 0;
    }

    // Init the game.
    //
    static void InitGame()
    {
        Console.Clear();
        players = NumberOfPlayers();
        for (int player = 0; player < players; player++)
        {
            isPlaying[player] = true;
        }
        Console.Clear();
        PrintTitle();
        InitGrids();
        PrintGrids();
    }

    // Play the game.
    //
    static void Play()
    {
        InitGame();
        while (IsSomeonePlaying())
        {
            PlayTurns();
            PrintGrids();
            if (HasSomeoneWon())
            {
                break;
            }
        }
    }

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

    // Init the program, i.e. just once before the first game.
    //
    static void InitOnce()
    {
        // Init the pristine grid.
        const int FIRST_CHAR_CODE = (int) 'A';
        for (int i = 0; i < CELLS - 1; i++)
        {
            pristineGrid[i] = ((char) (FIRST_CHAR_CODE + i)).ToString();
        }
        pristineGrid[CELLS - 1] = BLANK;

        // Init the grid
        for (int i = 0; i < MAX_PLAYERS; i++)
        {
            grid[i] = new string[CELLS];
            grid[i] = pristineGrid;
        }
    }

    // Return `true` if the player does not want to play another game; otherwise
    // return `false`.
    //
    static bool Enough()
    {
        (int y, int x) = (GridPromptPosition(player : 0));
        Console.SetCursorPosition(x, y);
        return ! Yes("Another game? ");
    }

    static void Main()
    {
        InitOnce();

        Console.Clear();
        PrintCredits();

        PressEnter("\nPress the Enter key to read the instructions. ");
        Console.Clear();
        PrintInstructions();

        PressEnter("\nPress the Enter key to start. ");
        while (true)
        {
            Play();
            if (Enough())
            {
                break;
            }
        }
        Console.WriteLine("So long…");
    }
}

Págines relatet

Basics off
Metaprojecte pri li projectes «Basics of…».
Basics of 8th
Conversion de old BASIC-programas a 8th por aprender lu elementari de ti-ci lingue.
Basics of Ada
Conversion de old BASIC-programas a Ada por aprender lu elementari de ti-ci lingue.
Basics of Arturo
Conversion de old BASIC-programas a Arturo por aprender lu elementari de ti-ci lingue.
Basics of C3
Conversion de old BASIC-programas a C3 por aprender lu elementari de ti-ci lingue.
Basics of Chapel
Conversion de old BASIC-programas a Chapel por aprender lu elementari de ti-ci lingue.
Basics of Clojure
Conversion de old BASIC-programas a Clojure por aprender lu elementari de ti-ci lingue.
Basics of Crystal
Conversion de old BASIC-programas a Crystal por aprender lu elementari de ti-ci lingue.
Basics of D
Conversion de old BASIC-programas a D por aprender lu elementari de ti-ci lingue.
Basics of Elixir
Conversion de old BASIC-programas a Elixir por aprender lu elementari de ti-ci lingue.
Basics of F#
Conversion de old BASIC-programas a F# por aprender lu elementari de ti-ci lingue.
Basics of Factor
Conversion de old BASIC-programas a Factor por aprender lu elementari de ti-ci lingue.
Basics of FreeBASIC
Conversion de old BASIC-programas a FreeBASIC por aprender lu elementari de ti-ci lingue.
Basics of Gleam
Conversion de old BASIC-programas a Gleam por aprender lu elementari de ti-ci lingue.
Basics of Go
Conversion de old BASIC-programas a Go por aprender lu elementari de ti-ci lingue.
Basics of Hare
Conversion de old BASIC-programas a Hare por aprender lu elementari de ti-ci lingue.
Basics of Haxe
Conversion de old BASIC-programas a Haxe por aprender lu elementari de ti-ci lingue.
Basics of Icon
Conversion de old BASIC-programas a Icon por aprender lu elementari de ti-ci lingue.
Basics of Io
Conversion de old BASIC-programas a Io por aprender lu elementari de ti-ci lingue.
Basics of Janet
Conversion de old BASIC-programas a Janet por aprender lu elementari de ti-ci lingue.
Basics of Julia
Conversion de old BASIC-programas a Julia por aprender lu elementari de ti-ci lingue.
Basics of Kotlin
Conversion de old BASIC-programas a Kotlin por aprender lu elementari de ti-ci lingue.
Basics of Lobster
Conversion de old BASIC-programas a Lobster por aprender lu elementari de ti-ci lingue.
Basics of Lua
Conversion de old BASIC-programas a Lua por aprender lu elementari de ti-ci lingue.
Basics of Nature
Conversion de old BASIC-programas a Nature por aprender lu elementari de ti-ci lingue.
Basics of Neat
Conversion de old BASIC-programas a Neat por aprender lu elementari de ti-ci lingue.
Basics of Neko
Conversion de old BASIC-programas a Neko por aprender lu elementari de ti-ci lingue.
Basics of Nelua
Conversion de old BASIC-programas a Nelua por aprender lu elementari de ti-ci lingue.
Basics of Nim
Conversion de old BASIC-programas a Nim por aprender lu elementari de ti-ci lingue.
Basics of Nit
Conversion de old BASIC-programas a Nit por aprender lu elementari de ti-ci lingue.
Basics of Oberon-07
Conversion de old BASIC-programas a Oberon-07 por aprender lu elementari de ti-ci lingue.
Basics of OCaml
Conversion de old BASIC-programas a OCaml por aprender lu elementari de ti-ci lingue.
Basics of Odin
Conversion de old BASIC-programas a Odin por aprender lu elementari de ti-ci lingue.
Basics of Pike
Conversion de old BASIC-programas a Pike por aprender lu elementari de ti-ci lingue.
Basics of Pony
Conversion de old BASIC-programas a Pony por aprender lu elementari de ti-ci lingue.
Basics of Python
Conversion de old BASIC-programas a Python por aprender lu elementari de ti-ci lingue.
Basics of Racket
Conversion de old BASIC-programas a Racket por aprender lu elementari de ti-ci lingue.
Basics of Raku
Conversion de old BASIC-programas a Raku por aprender lu elementari de ti-ci lingue.
Basics of Retro
Conversion de old BASIC-programas a Retro por aprender lu elementari de ti-ci lingue.
Basics of Rexx
Conversion de old BASIC-programas a Rexx por aprender lu elementari de ti-ci lingue.
Basics of Ring
Conversion de old BASIC-programas a Ring por aprender lu elementari de ti-ci lingue.
Basics of Rust
Conversion de old BASIC-programas a Rust por aprender lu elementari de ti-ci lingue.
Basics of Scala
Conversion de old BASIC-programas a Scala por aprender lu elementari de ti-ci lingue.
Basics of Scheme
Conversion de old BASIC-programas a Scheme por aprender lu elementari de ti-ci lingue.
Basics of Styx
Conversion de old BASIC-programas a Styx por aprender lu elementari de ti-ci lingue.
Basics of Swift
Conversion de old BASIC-programas a Swift por aprender lu elementari de ti-ci lingue.
Basics of V
Conversion de old BASIC-programas a V por aprender lu elementari de ti-ci lingue.
Basics of Vala
Conversion de old BASIC-programas a Vala por aprender lu elementari de ti-ci lingue.
Basics of Zig
Conversion de old BASIC-programas a Zig por aprender lu elementari de ti-ci lingue.

Extern ligamentes relatet